From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380819; cv=none; d=zohomail.com; s=zohoarc; b=NoejaNQRDPCT2cij7n4lCRQkyZ1jgPTUei8lt+E2XpeQ0PxWvRWGHLVP3Hoa5x9knC16k78hOyeGBJ0ZiJGvq5i97g8KHzMqu9FF+iZRHXFhVfy4VdNrpe6WbAQRXTFhzvg+ED/z1YKosY4jtGvXwnXklXyCMiaqXh1nHn56mII= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380819; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=N4VjtNGTVCTr3fiohuEIHANGrMrdHqVx/1EQ5lSRyCE=; b=EUVj1URAOHiTOLw4KU8ouY/arooUHZbhm6jRRiuaGGOfZb8TFc2XYlnpncnK/Xm/mIUSzQtVdd+ujKnuLPfeoiPwvJLzq1tB+t9ZHS+iVQmsNNb195j3D2f9Vd521gHVfGV2mLy9+OAonUvWuQgEWJW+KFipclWWuVCA3EXIf7Q= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380819287548.1452036882815; Wed, 29 Jul 2026 20:06:59 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH5l-0001im-9H; Wed, 29 Jul 2026 23:05:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5j-0001iG-AQ for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:51 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5h-0002qW-Ag for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:51 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=N4VjtNGTVCTr3fiohuEIHANGrMrdHqVx/1EQ5lSRyCE=; b=CZy6N2iP0KZW2Dx IKM90W85A6e81gynuWJxH2zCHiM2VFp7HQB8NGdH8h4lglM6B52kmqojywe8wwkWXTRvvA5O9ja8U 5jrdW/s+3sggkAQclxaG85HmcY4DBsT4t7t931s9sIbt7gmJdFpT683s+a79am6HS2x1syb7XLiBy eQ=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 01/50] accel/tcg: Add bitreverse and funnel-shift runtime helper functions Date: Thu, 30 Jul 2026 05:09:35 +0200 Message-ID: <20260730031025.12926-2-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380821067158500 Content-Type: text/plain; charset="utf-8" Adds necessary helper functions for mapping LLVM IR onto TCG. Specifically, helpers corresponding to the bitreverse and funnel-shift intrinsics in LLVM. Note: these may be converted to more efficient implementations in the future, but for the time being it allows helper-to-tcg to support a wider subset of LLVM IR. Signed-off-by: Anton Johansson -- TODO: `tcg_gen_*()` variants will be added in the next version, it slipped through (Richard). Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- accel/tcg/tcg-runtime.c | 28 ++++++++++++++++++++++++++++ accel/tcg/tcg-runtime.h | 6 ++++++ 2 files changed, 34 insertions(+) diff --git a/accel/tcg/tcg-runtime.c b/accel/tcg/tcg-runtime.c index 7c0aab98a8..d42c00736b 100644 --- a/accel/tcg/tcg-runtime.c +++ b/accel/tcg/tcg-runtime.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qemu/host-utils.h" #include "exec/cpu-common.h" +#include "qemu/int128.h" #include "exec/helper-proto-common.h" #include "accel/tcg/cpu-loop.h" #include "accel/tcg/getpc.h" @@ -54,8 +55,30 @@ uint32_t HELPER(remu_i32)(uint32_t arg1, uint32_t arg2) return arg1 % arg2; } =20 +uint32_t HELPER(bitreverse8_i32)(uint32_t x) +{ + return revbit8((uint8_t) x); +} + +uint32_t HELPER(bitreverse16_i32)(uint32_t x) +{ + return revbit16((uint16_t) x); +} + +uint32_t HELPER(bitreverse32_i32)(uint32_t x) +{ + return revbit32(x); +} + /* 64-bit helpers */ =20 +uint64_t HELPER(fshl_i64)(uint64_t a, uint64_t b, uint64_t c) +{ + Int128 d =3D int128_make128(b, a); + Int128 shift =3D int128_lshift(d, c); + return int128_gethi(shift); +} + int64_t HELPER(div_i64)(int64_t arg1, int64_t arg2) { return arg1 / arg2; @@ -76,6 +99,11 @@ uint64_t HELPER(remu_i64)(uint64_t arg1, uint64_t arg2) return arg1 % arg2; } =20 +uint64_t HELPER(bitreverse64_i64)(uint64_t x) +{ + return revbit64(x); +} + uint64_t HELPER(muluh_i64)(uint64_t arg1, uint64_t arg2) { uint64_t l, h; diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index 0b832176b3..197d658b40 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -2,11 +2,17 @@ DEF_HELPER_FLAGS_2(div_i32, TCG_CALL_NO_RWG_SE, s32, s32,= s32) DEF_HELPER_FLAGS_2(rem_i32, TCG_CALL_NO_RWG_SE, s32, s32, s32) DEF_HELPER_FLAGS_2(divu_i32, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(remu_i32, TCG_CALL_NO_RWG_SE, i32, i32, i32) +DEF_HELPER_FLAGS_1(bitreverse8_i32, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_FLAGS_1(bitreverse16_i32, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_FLAGS_1(bitreverse32_i32, TCG_CALL_NO_RWG_SE, i32, i32) =20 DEF_HELPER_FLAGS_2(div_i64, TCG_CALL_NO_RWG_SE, s64, s64, s64) DEF_HELPER_FLAGS_2(rem_i64, TCG_CALL_NO_RWG_SE, s64, s64, s64) DEF_HELPER_FLAGS_2(divu_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_2(remu_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_1(bitreverse64_i64, TCG_CALL_NO_RWG_SE, i64, i64) + +DEF_HELPER_FLAGS_3(fshl_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64) =20 DEF_HELPER_FLAGS_2(mulsh_i64, TCG_CALL_NO_RWG_SE, s64, s64, s64) DEF_HELPER_FLAGS_2(muluh_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64) --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380871; cv=none; d=zohomail.com; s=zohoarc; b=IBA/Vmh6M+MTjNJyO9Hd/GrfGiI2qxcXcSPZ5Jy2/uNx7vq2tx3+dFoJdwCZX3VEe2L7fWvnpmEavMWq28HRYxfxKeqo951fPDBnE+um5JXkLPjb88p4rvhgg0uSjsxX4kerEsp1njN+hQR8i2M+HVwgOsQCIQwRegG1ZRyaxl8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380871; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=41NJDuCDVPFzF4xI3SnhPELSy7zvSxiIHZf5nS+T8A0=; b=cO6cazK/6Zfa8UlH5srRI67ugrydjUEEQurHMfNUObwSnuXe5g+kDDHm9Lu4DYT/aMCN0xT8fyDqgweOTP13kGRyd0a/ZNgqbDYDUCqHAdYF3m9Y2PNwZhrOEW97mN5ZPu2LK2gpcYMK3fGb1KLcy7+UueBwQh8UfkxBDkDwnfU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380871294841.6889702361375; Wed, 29 Jul 2026 20:07:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH5s-0001mP-3s; Wed, 29 Jul 2026 23:06:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5n-0001jT-D2 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:56 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5l-0002qd-Os for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:55 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=41NJDuCDVPFzF4xI3SnhPELSy7zvSxiIHZf5nS+T8A0=; b=Lzj7i3AOPgLhXtn j409lPd6n4tYIVRefjfAVUTmHLRCuptbNELaB7awuk/jo2ZmmOCxUJor7p4neIIlJ7Coiu2ehi1YD oQRLFSsjDp2BMku5a4RgN8qTeukoFKEQ/TN/NJbm+PRp55YlKmDiCAPaP0TqmMl/fVjFk8JcA6rDr Ag=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 02/50] accel/tcg: Add getpc helper Date: Thu, 30 Jul 2026 05:09:36 +0200 Message-ID: <20260730031025.12926-3-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380873118158500 Content-Type: text/plain; charset="utf-8" Introduces a helper function to return the current pc (returnaddress of the helper), this allows helper-to-tcg to correctly translate nested helper functions that checks for faulting memory operations. This is useful as an optimization where a helper functions has a commonly taken fast path that doesn't fault e.g. void HELPER(outer)(...) { ... // non faulting operations if (some_uncommon_condition) { helper_inner(..., GETPC()) } } the outer helper along with the condition can then be emitted as TCG, and helper_inner() will be emitted as a gen_helper_inner(, ra), where ra is the result of gen_helper_getpc(). NOTE: This is not ideal since we're introducing extra helper calls, and the solution doesn't deal with the "inner" function not being a helper. A better solution and what we'll probably do in the next version of the patchset is to instead emit a helper definition for the "inner" function that uses GETPC(). Signed-off-by: Anton Johansson --- accel/tcg/tcg-runtime.c | 5 +++++ accel/tcg/tcg-runtime.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/accel/tcg/tcg-runtime.c b/accel/tcg/tcg-runtime.c index d42c00736b..87b9530a50 100644 --- a/accel/tcg/tcg-runtime.c +++ b/accel/tcg/tcg-runtime.c @@ -162,3 +162,8 @@ void HELPER(exit_atomic)(CPUArchState *env) { cpu_loop_exit_atomic(env_cpu(env), GETPC()); } + +uint64_t HELPER(getpc)(void) +{ + return GETPC(); +} diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index 197d658b40..e25712d1fc 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -30,6 +30,8 @@ DEF_HELPER_FLAGS_1(lookup_tb_ptr, TCG_CALL_NO_WG_SE, cptr= , env) =20 DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env) =20 +DEF_HELPER_FLAGS_0(getpc, TCG_CALL_NO_RWG_SE, i64) + #ifndef IN_HELPER_PROTO /* * Pass calls to memset directly to libc, without a thunk in qemu. --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380881; cv=none; d=zohomail.com; s=zohoarc; b=ET2pC1IK5BOApMCg9zQKLsWgvnT8fVlWSnKtoaJOBc2cuB0HZHCc/OF5lGSPT+4TLh6Uu66blwj3xmPiry+xX4h5u4qYdyNQtFloCOzEQR14CRdVUhixDMpC5kzFG5VOk6qtV+oRdjEsrNaMb6pbEsoCV4K4KSSw0M9xJ63ykfQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380881; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=/yrhCiwZxhpBbFg+pWTw+aPmGPtG9P1Y5tKxmOCNipk=; b=WKwDVDk6MbANpDarN7d7WwjNcdz5P47jdqlindrm3cRQTWFdSTv8K3saIvaPoKqfkW0GA54l0cXPFNabGjR9AZBkgKfSGPxWPl2pKjp4/UbI6taru66rEYF4ZKajb2AkDiAya+tBywYTVgvun+3maTSLHEzhg1XM3OJ0IAo2oy8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380881862825.4373609800016; Wed, 29 Jul 2026 20:08:01 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH5s-0001mu-Ps; Wed, 29 Jul 2026 23:06:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5r-0001lP-4Q for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:59 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5l-0002qg-Oh for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:57 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=/yrhCiwZxhpBbFg+pWTw+aPmGPtG9P1Y5tKxmOCNipk=; b=oLAQI28zPmNXjfF fZCz03lpFjp9mdiQ4T21MYVE7jFfW7VdfnhvliW0UNsBAZ3MY3SW6Ee7m9D+dsz+U9kYOMqDKaGIP hKIxBWmXlVQ9M2LcADcwSTUfMcRoL99AQUZ9xR0VOj3AhkEWo4GzEiSwifRk0zljSda7bqyAPeimM Dw=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 03/50] tcg: Introduce tcg-global-mappings Date: Thu, 30 Jul 2026 05:09:37 +0200 Message-ID: <20260730031025.12926-4-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380883312158500 Content-Type: text/plain; charset="utf-8" Adds a cpu_mapping struct to describe, in a declarative fashion, the mapping between fields in a struct, and a corresponding TCG global. As such, tcg_global_mem_new() can be automatically called given an array of cpu_mappings. This change is not limited to helper-to-tcg, but will be required in future commits to map between offsets into CPUArchState and TCGv globals in a target-agnostic way. Signed-off-by: Anton Johansson --- include/tcg/tcg-global-mappings.h | 118 ++++++++++++++++++++++++++++++ tcg/meson.build | 1 + tcg/tcg-global-mappings.c | 62 ++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 include/tcg/tcg-global-mappings.h create mode 100644 tcg/tcg-global-mappings.c diff --git a/include/tcg/tcg-global-mappings.h b/include/tcg/tcg-global-map= pings.h new file mode 100644 index 0000000000..341dcd20b3 --- /dev/null +++ b/include/tcg/tcg-global-mappings.h @@ -0,0 +1,118 @@ +/* + * Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef TCG_GLOBAL_MAP_H +#define TCG_GLOBAL_MAP_H + +/** + * cpu_tcg_mapping: Declarative mapping of offsets into a struct to global + * TCGvs. Parseable by LLVM-based tools. + * @tcg_var_name: String name of the TCGv to use as destination of the map= ping. + * @tcg_var_base_address: Address of the above TCGv. + * @cpu_type_name: String name of the base type being mapped, e.g. "CPUArc= hState". + * @cpu_var_names: Array of printable names of TCGvs, used when calling + * tcg_global_mem_new from init_cpu_tcg_mappings. Contains + * @number_of_elements strings. + * @cpu_var_base_offset: Base offset of field in the source struct. + * @cpu_var_size: Size of field in the source struct, if the field is an a= rray, + * this holds the size of the element type. + * @cpu_var_stride: Stride between array elements in the source struct. T= his + * can be greater than the element size when mapping a fi= eld + * in an array of structs. + * @number_of_elements: Number of elements of array in the source struct. + */ +typedef struct cpu_tcg_mapping { + const char *tcg_var_name; + void *tcg_var_base_address; + + const char *cpu_type_name; + const char *const *cpu_var_names; + size_t cpu_var_base_offset; + size_t cpu_var_size; + size_t cpu_var_stride; + + size_t number_of_elements; +} cpu_tcg_mapping; + +#define STRUCT_SIZEOF_FIELD(S, member) sizeof(((S *)0)->member) + +#define STRUCT_ARRAY_SIZE(S, array) = \ + (STRUCT_SIZEOF_FIELD(S, array) / STRUCT_SIZEOF_FIELD(S, array[0])) + +/* + * Following are a few macros that aid in constructing + * `cpu_tcg_mapping`s for a few common cases. + */ + +/* Map between single CPU register and to TCG global */ +#define CPU_TCG_MAP(struct_type, tcg_var, cpu_var) = \ + (cpu_tcg_mapping) = \ + { = \ + .tcg_var_name =3D stringify(tcg_var), = \ + .tcg_var_base_address =3D &tcg_var, = \ + .cpu_type_name =3D stringify(struct_type), = \ + .cpu_var_names =3D (const char *[]){stringify(cpu_var)}, = \ + .cpu_var_base_offset =3D offsetof(struct_type, cpu_var), = \ + .cpu_var_size =3D STRUCT_SIZEOF_FIELD(struct_type, cpu_var), = \ + .cpu_var_stride =3D 0, .number_of_elements =3D 1, = \ + } + +/* Map between array of CPU registers and array of TCG globals. */ +#define CPU_TCG_MAP_ARRAY(struct_type, tcg_var, cpu_var, names) = \ + (cpu_tcg_mapping) = \ + { = \ + .tcg_var_name =3D stringify(tcg_var), = \ + .tcg_var_base_address =3D tcg_var, = \ + .cpu_type_name =3D stringify(struct_type), = \ + .cpu_var_names =3D names, = \ + .cpu_var_base_offset =3D offsetof(struct_type, cpu_var), = \ + .cpu_var_size =3D STRUCT_SIZEOF_FIELD(struct_type, cpu_var[0]), = \ + .cpu_var_stride =3D STRUCT_SIZEOF_FIELD(struct_type, cpu_var[0]), = \ + .number_of_elements =3D STRUCT_ARRAY_SIZE(struct_type, cpu_var), = \ + } + +/* + * Map between single member in an array of structs to an array + * of TCG globals, e.g. maps + * + * cpu_state.array_of_structs[i].member + * + * to + * + * tcg_global_member[i] + */ +#define CPU_TCG_MAP_ARRAY_OF_STRUCTS(struct_type, tcg_var, cpu_struct, = \ + cpu_var, names) = \ + (cpu_tcg_mapping) = \ + { = \ + .tcg_var_name =3D stringify(tcg_var), = \ + .tcg_var_base_address =3D tcg_var, = \ + .cpu_type_name =3D stringify(struct_type), = \ + .cpu_var_names =3D names, = \ + .cpu_var_base_offset =3D offsetof(struct_type, cpu_struct[0].cpu_v= ar), \ + .cpu_var_size =3D = \ + STRUCT_SIZEOF_FIELD(struct_type, cpu_struct[0].cpu_var), = \ + .cpu_var_stride =3D STRUCT_SIZEOF_FIELD(struct_type, cpu_struct[0]= ), \ + .number_of_elements =3D STRUCT_ARRAY_SIZE(struct_type, cpu_struct)= , \ + } + +extern cpu_tcg_mapping tcg_global_mappings[]; +extern size_t tcg_global_mapping_count; + +void init_cpu_tcg_mappings(cpu_tcg_mapping *mappings, size_t size); + +#endif /* TCG_GLOBAL_MAP_H */ diff --git a/tcg/meson.build b/tcg/meson.build index 706a6eb260..c7c16eeb05 100644 --- a/tcg/meson.build +++ b/tcg/meson.build @@ -13,6 +13,7 @@ tcg_ss.add(files( 'tcg-op-ldst.c', 'tcg-op-gvec.c', 'tcg-op-vec.c', + 'tcg-global-mappings.c', )) =20 if get_option('tcg_interpreter') diff --git a/tcg/tcg-global-mappings.c b/tcg/tcg-global-mappings.c new file mode 100644 index 0000000000..a75fad0c21 --- /dev/null +++ b/tcg/tcg-global-mappings.c @@ -0,0 +1,62 @@ +/* + * Copyright(c) 2024 rev.ng Labs Srl. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "qemu/osdep.h" +#include "tcg/tcg-global-mappings.h" +#include "tcg/tcg-op-common.h" +#include "tcg/tcg.h" + +void init_cpu_tcg_mappings(cpu_tcg_mapping *mappings, size_t size) +{ + uintptr_t tcg_addr; + size_t cpu_offset; + const char *name; + cpu_tcg_mapping m; + + /* + * Paranoid assertion, this should always hold since + * they're typedef'd to pointers. But you never know! + */ + g_assert(sizeof(TCGv_i32) =3D=3D sizeof(TCGv_i64)); + + /* + * Loop over entries in tcg_global_mappings and + * create the `mapped to` TCGv's. + */ + for (int i =3D 0; i < size; ++i) { + m =3D mappings[i]; + + for (int j =3D 0; j < m.number_of_elements; ++j) { + /* + * Here we are using the fact that + * sizeof(TCGv_i32) =3D=3D sizeof(TCGv_i64) =3D=3D sizeof(TCGv) + */ + assert(sizeof(TCGv_i32) =3D=3D sizeof(TCGv_i64)); + tcg_addr =3D (uintptr_t)m.tcg_var_base_address + j * sizeof(TC= Gv_i32); + cpu_offset =3D m.cpu_var_base_offset + j * m.cpu_var_stride; + name =3D m.cpu_var_names[j]; + + if (m.cpu_var_size < 8) { + *(TCGv_i32 *)tcg_addr =3D + tcg_global_mem_new_i32(tcg_env, cpu_offset, name); + } else { + *(TCGv_i64 *)tcg_addr =3D + tcg_global_mem_new_i64(tcg_env, cpu_offset, name); + } + } + } +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380786; cv=none; d=zohomail.com; s=zohoarc; b=jQYoYgqR9tTzktYDpeBSkY9XLlrAHlExtZ4v8HWLp2LX1go572HkmGSY4vLaBnItIc2DglQBlBBM/ygTj950GVvqbns5OvluRWl1+yk2JhVJlorm+ltoitWDlkM6p+TcPKsFqsz1XPNBKeNrYGe2EtgeiTDuykEEibIFKhq6N/A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380786; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=ZRtPEX6hvMSWm8NRWFwIBAinEzO0tNlAujA90C2lKC8=; b=O4q7yCo8iCYn5cAvVrOsgFXkgp8Hd4etHwHqmUo8O4+kwyRgbcwsmX7CAVfbMXRi3E1ppKIHHVN5jJMokIpX2F6o/ZjnI8Jz/0WgeguN3sK9bWy/3bDBmQDRQ1w2pZoMXEGt6O+aD7hj6vcOyOIsMuwyCzYv8A0bJEhKKeILTJw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380786210401.96128488372017; Wed, 29 Jul 2026 20:06:26 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH5k-0001iP-Nd; Wed, 29 Jul 2026 23:05:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5j-0001i9-0n for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:51 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5h-0002qo-Ah for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:50 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=ZRtPEX6hvMSWm8NRWFwIBAinEzO0tNlAujA90C2lKC8=; b=HeOGJ0iapFI27ZR jJINiWaIBS6I/YuFffItu6Ep2fhcAqyBrvtR0UakAek4nGdYYHAjKagb9d2j0SOhL2H6wCS4HdipH AeHyzRKmE6fxWjwAYAIh+6lFpcRwr8xcfRBoXlp5F05CatD/JGhsTKcOLa0LrQx33nl06lHpB4qcb /w=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 04/50] tcg: Increase maximum TB size Date: Thu, 30 Jul 2026 05:09:38 +0200 Message-ID: <20260730031025.12926-5-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380787873158500 Content-Type: text/plain; charset="utf-8" Doubles amount of space allocated for translation blocks. This is needed, particularly for Hexagon, where a single instruction packet may consist of up to four vector instructions. If each vector instruction then gets expanded into gvec operations that utilize a small host vector size the TB blows up quite quickly. Signed-off-by: Anton Johansson --- include/tcg/tcg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 7669dc1c2d..9f0a35f1be 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -40,7 +40,7 @@ /* XXX: make safe guess about sizes */ #define MAX_OP_PER_INSTR 266 =20 -#define CPU_TEMP_BUF_NLONGS 128 +#define CPU_TEMP_BUF_NLONGS 256 #define TCG_STATIC_FRAME_SIZE (CPU_TEMP_BUF_NLONGS * sizeof(long)) =20 typedef int64_t tcg_target_long; --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381128; cv=none; d=zohomail.com; s=zohoarc; b=DMj2ECQE4PAN8Z8N96pbhhRtl2whIzZowwsOuLKFMjysUvaI43Chj2/4BWIJVONTFeJ6puRsqeIrIn0cxrYCQRkqjQAY6FtxQ8z2gn0d+05xR9tbW2gsDiDnr6+cV2sBjnZxlpajS2D8E9qN6fF5TiKPVrwlCFHGJ2co+ay+gss= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381128; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=XaUIMITGO14lWCKe7QLFme4f15IAQ8CLcWY+DUS8ahY=; b=N95XEqILAvPBv/N43CEMVIZcBPUXkWLWD3m7pAgrvqwWm8FrtJ3D31R2GIslCZdZNWS6FzE5ieUkTb2QMU0g39Ole13kTEFivd1+8PGlCOyeM5KJqZp76YSoJ4jLNZ3qrQ8up/R4Lb1+h31WMTm1/U4pKPU/ZK3CLwBhvZlELP0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381128875255.43067126737765; Wed, 29 Jul 2026 20:12:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH5r-0001lo-JW; Wed, 29 Jul 2026 23:05:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5l-0001iq-Tx for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:53 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5i-0002qs-55 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:52 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=XaUIMITGO14lWCKe7QLFme4f15IAQ8CLcWY+DUS8ahY=; b=OHd+IBnEwZDnEis haPgSJVnRuxcYmGetX9if6zYXRNr29brCivPj74Arb8B99rRrG4oWTXTdgQB9JLKLQYkq/gABvoO1 JkpXxVGt8rfUzU4NcrC+kKjbnuHhKwOjPTw+gF20CcUl7dBMcRadC/wnjiMLmgoCVUqDtvkoPab7k +Y=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 05/50] tcg: Expose tcg_gen_ussub_sat() Date: Thu, 30 Jul 2026 05:09:39 +0200 Message-ID: <20260730031025.12926-6-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381130109158500 Content-Type: text/plain; charset="utf-8" Maps nicely to LLVMs usub.sat instrinsic. Signed-off-by: Anton Johansson Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- include/tcg/tcg-op-common.h | 2 ++ tcg/tcg-op-gvec.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h index 1fe342db0d..9df8a72c08 100644 --- a/include/tcg/tcg-op-common.h +++ b/include/tcg/tcg-op-common.h @@ -192,6 +192,7 @@ void tcg_gen_sar_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_= i32 arg2); void tcg_gen_mul_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_neg_i32(TCGv_i32 ret, TCGv_i32 arg); void tcg_gen_not_i32(TCGv_i32 ret, TCGv_i32 arg); +void tcg_gen_ussub_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b); =20 /* 64 bit ops */ =20 @@ -258,6 +259,7 @@ void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i= 64 arg1, TCGv_i64 arg2); void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 a= rg2); void tcg_gen_mulsu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 = arg2); void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg); +void tcg_gen_ussub_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b); void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg); void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg); void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg); diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index bc323e2500..cd0a2fd83d 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -2399,14 +2399,14 @@ void tcg_gen_gvec_usadd(unsigned vece, uint32_t dof= s, uint32_t aofs, tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g[vece]); } =20 -static void tcg_gen_ussub_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) +void tcg_gen_ussub_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) { TCGv_i32 min =3D tcg_constant_i32(0); tcg_gen_sub_i32(d, a, b); tcg_gen_movcond_i32(TCG_COND_LTU, d, a, b, min, d); } =20 -static void tcg_gen_ussub_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) +void tcg_gen_ussub_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) { TCGv_i64 min =3D tcg_constant_i64(0); tcg_gen_sub_i64(d, a, b); --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381091; cv=none; d=zohomail.com; s=zohoarc; b=jN2us2BVQdYCV5kN94xYFkCk0Nd5J9VxZ8mD+cAjmRCXkrGUqi7YniKFpcni0wBMKMPGVs1UHQNZOZdrRInNZKm+dQ5FIJlv3UPXSMhrvU45x+IC/nKEU25jjAkU9PskTUP08shZdeMSpuGqMFITJFTdr67Ej88SDjinGIzeYes= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381091; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=fUstv3mSVXiLKitmFFzJoN0BAt6jWPawXtZvtpdzUus=; b=dKyrt2c3Facw5mdkUfwjEyPR/R/Sypi0B/yV+R/JWYWSCNXvHMMK7rA518fcHkA/MnEGBy3P4Hnd4S6uCeFLuwvBntiewg+c2PpiWKsx3LGv54Mpoquw8s7FMCYBMG7BD6HkUk27wI9vzwXCSlppIjjOxjkhWhFPhJ7hHH8Daxo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381091143655.4853748462408; Wed, 29 Jul 2026 20:11:31 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH5t-0001nX-I6; Wed, 29 Jul 2026 23:06:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5r-0001lO-5w for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:59 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5l-0002rM-Oi for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:56 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=fUstv3mSVXiLKitmFFzJoN0BAt6jWPawXtZvtpdzUus=; b=EbYfeoB0VKsD7mg 4s9fSnEniMZgzAGGikcvKkx+Eg0iKFMCslyEws+tKR76615k4Ch3ZQIvpTK1OqDFi/ipHq/OFgSGU fRUAzCdx9bFnl9wKRjJfRn1zIvlzWx0ms7J0UeZkTfLxB34AJ36GQPQItVq5Pbb8A8U7CZJsJx+2Z ns=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 06/50] Add helper-to-tcg subproject Date: Thu, 30 Jul 2026 05:09:40 +0200 Message-ID: <20260730031025.12926-7-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381092085158500 Content-Type: text/plain; charset="utf-8" Adds a new bare bones subproject along with options to enable or disable it. The LLVM dependency is managed manually through `llvm-config` for two reasons: meson struggles with multiple system LLVM versions anyway and usually returns the newest one even if it doesn't satisfy the version requirement, and; It allows the user to override the default if they choose. As such, an option is added to the subproject to manually override `llvm-config`. A new target config option TARGET_HELPER_TO_TCG is also introduced, which will used in future commits to conditionally add or remove remove code and memory required by helper-to-tcg. Current meson option is limited to Hexagon, this might change in the future if more uses are found on different frontends. Signed-off-by: Anton Johansson --- meson.build | 10 ++++ meson_options.txt | 2 + scripts/meson-buildoptions.sh | 5 ++ subprojects/helper-to-tcg/meson.build | 61 +++++++++++++++++++++ subprojects/helper-to-tcg/meson_options.txt | 2 + 5 files changed, 80 insertions(+) create mode 100644 subprojects/helper-to-tcg/meson.build create mode 100644 subprojects/helper-to-tcg/meson_options.txt diff --git a/meson.build b/meson.build index 49a5baf5b5..a1411b0eb6 100644 --- a/meson.build +++ b/meson.build @@ -3273,7 +3273,16 @@ host_kconfig =3D \ (hv_balloon ? ['CONFIG_HV_BALLOON_POSSIBLE=3Dy'] : []) + \ (have_rust ? ['CONFIG_HAVE_RUST=3Dy'] : []) =20 +helper_to_tcg =3D subproject('helper-to-tcg', + required: get_option('hexagon_helper_to_tcg') \ + .disable_auto_if('hexagon-linux-user' not in target_dirs and \ + 'hexagon-softmmu' not in target_dirs)) + ignored =3D [ 'TARGET_XML_FILES', 'TARGET_ABI_DIR' ] +if not helper_to_tcg.found() + # do not define it if it is not usable + ignored +=3D ['TARGET_HELPER_TO_TCG'] +endif =20 default_targets =3D 'CONFIG_DEFAULT_TARGETS' in config_host actual_target_dirs =3D [] @@ -4266,6 +4275,7 @@ foreach target : target_dirs if host_os =3D=3D 'linux' target_inc +=3D include_directories('linux-headers', is_system: true) endif + if target.endswith('-softmmu') target_type=3D'system' if target_base_arch in target_system_arch diff --git a/meson_options.txt b/meson_options.txt index a07cb47d35..63309ceaff 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -377,6 +377,8 @@ option('qemu_ga_version', type: 'string', value: '', =20 option('hexagon_idef_parser', type : 'boolean', value : true, description: 'use idef-parser to automatically generate TCG code fo= r the Hexagon frontend') +option('hexagon_helper_to_tcg', type : 'feature', value : 'enabled', + description: 'use the helper-to-tcg translator to automatically gen= erate TCG code from helpers') =20 option('x86_version', type : 'combo', choices : ['0', '1', '2', '3', '4'],= value: '1', description: 'tweak required x86_64 architecture version beyond com= piler default') diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index c003985047..9951d5ad95 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -125,6 +125,9 @@ meson_options_help() { printf "%s\n" ' gtk GTK+ user interface' printf "%s\n" ' guest-agent Build QEMU Guest Agent' printf "%s\n" ' guest-agent-msi Build MSI package for the QEMU Guest Ag= ent' + printf "%s\n" ' hexagon-helper-to-tcg' + printf "%s\n" ' use the helper-to-tcg translator to aut= omatically generate' + printf "%s\n" ' TCG code from helpers' printf "%s\n" ' hv-balloon hv-balloon driver (requires Glib 2.68+ = GTree API)' printf "%s\n" ' hvf HVF acceleration support' printf "%s\n" ' iconv Font glyph conversion support' @@ -337,6 +340,8 @@ _meson_option_parse() { --disable-guest-agent) printf "%s" -Dguest_agent=3Ddisabled ;; --enable-guest-agent-msi) printf "%s" -Dguest_agent_msi=3Denabled ;; --disable-guest-agent-msi) printf "%s" -Dguest_agent_msi=3Ddisabled ;; + --enable-hexagon-helper-to-tcg) printf "%s" -Dhexagon_helper_to_tcg=3D= enabled ;; + --disable-hexagon-helper-to-tcg) printf "%s" -Dhexagon_helper_to_tcg= =3Ddisabled ;; --enable-hexagon-idef-parser) printf "%s" -Dhexagon_idef_parser=3Dtrue= ;; --disable-hexagon-idef-parser) printf "%s" -Dhexagon_idef_parser=3Dfal= se ;; --enable-hv-balloon) printf "%s" -Dhv_balloon=3Denabled ;; diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build new file mode 100644 index 0000000000..8ab58adb39 --- /dev/null +++ b/subprojects/helper-to-tcg/meson.build @@ -0,0 +1,61 @@ +## +## Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program 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 General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +project('helper-to-tcg', ['cpp'], + version: '0.8', + default_options: ['cpp_std=3Dc++17']) + +python =3D import('python').find_installation() + +# Find LLVM using llvm-config manually. Needed as meson struggles when mu= ltiple +# versions of LLVM are installed on the same system (always returns the mo= st +# recent). +llvm_config =3D get_option('llvm_config_path') +cpp_args =3D run_command(llvm_config, '--cxxflags').stdout().strip().split= () +bindir =3D run_command(llvm_config, '--bindir').stdout().strip() +ldflags =3D run_command(llvm_config, '--ldflags').stdout().strip().split() +libs =3D run_command(llvm_config, '--libs').stdout().strip().split() +syslibs =3D run_command(llvm_config, '--system-libs').stdout().strip().spl= it() +incdir =3D run_command(llvm_config, '--includedir').stdout().strip().split= () +version =3D run_command(llvm_config, '--version').stdout().strip() +version_major =3D version.split('.')[0].to_int() + +# Check LLVM version manually +if version_major < 10 or version_major > 21 + error('LLVM version', version, 'not supported.') +endif + +sources =3D [ +] + +# NOTE: Add -Wno-template-id-cdtor for GCC versions >=3D 14. This warning= is +# related to a change in the C++ standard in C++20, that also applies to C= ++14 +# for some reason. See defect report DR2237 and commit +# https://gcc.gnu.org/git/gitweb.cgi?p=3Dgcc.git;h=3D4b38d56dbac6742b038= 551a36ec80200313123a1 +# (temporary) +compiler_info =3D meson.get_compiler('cpp') +compiler =3D compiler_info.get_id() +compiler_version =3D compiler_info.version().split('-').get(0) +compiler_version_major =3D compiler_version.split('.').get(0) +if compiler =3D=3D 'gcc' and compiler_version_major.to_int() >=3D 14 + cpp_args +=3D ['-Wno-template-id-cdtor', '-Wno-missing-template-keywor= d'] +endif + +pipeline =3D executable('helper-to-tcg', sources, + include_directories: ['include'] + [incdir], + link_args: [ldflags] + [libs] + [syslibs], + cpp_args: cpp_args) diff --git a/subprojects/helper-to-tcg/meson_options.txt b/subprojects/help= er-to-tcg/meson_options.txt new file mode 100644 index 0000000000..8a4b28a585 --- /dev/null +++ b/subprojects/helper-to-tcg/meson_options.txt @@ -0,0 +1,2 @@ +option('llvm_config_path', type : 'string', value : 'llvm-config', + description: 'override default llvm-config used for finding LLVM') --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380890; cv=none; d=zohomail.com; s=zohoarc; b=lLh4FOTk/0UEbejVyTM3ROseo74FkcDpt/dyZF8ZzbrXIRIHW7Jw9p+GtbkotLPaoBU9mVVvOt9Bwz8h7J1RcOLsLyFdAjhcWMP1F+LAqAmXMu4cixgDfZuyOc5GtKBpG84Z7rUdw4zJjZy+ASzKGerYpU9x9cyeV3/xFB4YxDs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380890; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=yysqe/Z5cYhXkFNQnRRfVlCRW9TXuGeF7cBWKGcBWgU=; b=OAQQeQP++UHTn5axEFklgdaGwG35QTq1Vh96/SlXNOAPhP+VTea+yYHs7C7AUsq3D35gfyaqEEHY/Oyn9mwL3rwtXAkbRYxE8WhMFntJB8u2viBeLYddMWXEvCgeOPLKSsv0nSLN8okd42Z88MNEHbO4pClBQ6PjJ/+yRwmtn9s= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380890304556.2532398094576; Wed, 29 Jul 2026 20:08:10 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH5s-0001mr-L9; Wed, 29 Jul 2026 23:06:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5r-0001lM-3O for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:59 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5m-0002rf-Dz for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:05:56 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=yysqe/Z5cYhXkFNQnRRfVlCRW9TXuGeF7cBWKGcBWgU=; b=CDfvdSDWKAaBq4g tqnoMXfQXvxs2uHteHF3/P4mSol8ZJ8hUmdnt+Chb2Afex25T/x+7AnqepYEpipNDWY2Y8/Lyk6I9 I4o7aQ3mQoj2V/itOS3N3rC53sa4jmuSY6WcN35sgFNYnPrgoLtbiMyoQ/EDZn7GbPb8Fxak2nP2w kg=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 07/50] helper-to-tcg: Introduce get-llvm-ir.py Date: Thu, 30 Jul 2026 05:09:41 +0200 Message-ID: <20260730031025.12926-8-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380891197158500 Content-Type: text/plain; charset="utf-8" Introduces a new python helper script to convert a set of QEMU .c files to LLVM IR .ll using clang. Compile flags are found by looking at compile_commands.json, and llvm-link is used to link together all LLVM modules into a single module. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- subprojects/helper-to-tcg/get-llvm-ir.py | 145 +++++++++++++++++++++++ subprojects/helper-to-tcg/meson.build | 8 ++ 2 files changed, 153 insertions(+) create mode 100755 subprojects/helper-to-tcg/get-llvm-ir.py diff --git a/subprojects/helper-to-tcg/get-llvm-ir.py b/subprojects/helper-= to-tcg/get-llvm-ir.py new file mode 100755 index 0000000000..982b87f791 --- /dev/null +++ b/subprojects/helper-to-tcg/get-llvm-ir.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program 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 General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +import argparse +import json +import os +import shlex +import sys +import subprocess + + +def log(msg): + print(msg, file=3Dsys.stderr) + + +def run_command(command): + proc =3D subprocess.Popen(command, stdout=3Dsubprocess.PIPE, stderr=3D= subprocess.STDOUT) + out =3D proc.communicate() + if proc.wait() !=3D 0: + log(f"Command: {' '.join(command)} exited with {proc.returncode}\n= ") + log(f"output:\n{out}\n") + + +def find_compile_commands(compile_commands_path, clang_path, input_path, t= arget): + with open(compile_commands_path, "r") as f: + compile_commands =3D json.load(f) + for compile_command in compile_commands: + path =3D compile_command["file"] + if os.path.basename(path) !=3D os.path.basename(input_path): + continue + + os.chdir(compile_command["directory"]) + command =3D compile_command["command"] + + # If building multiple targets there's a chance + # input files share the same path and name. + # This could cause us to find the wrong compile + # command, we use the target path to distinguish + # between these. + if not target in command: + continue + + argv =3D shlex.split(command) + argv[0] =3D clang_path + + return argv + + raise ValueError(f"Unable to find compile command for {input_path}") + + +def generate_llvm_ir( + compile_commands_path, clang_path, output_path, input_path, target +): + command =3D find_compile_commands( + compile_commands_path, clang_path, input_path, target + ) + + flags_to_remove =3D { + "-ftrivial-auto-var-init=3Dzero", + "-fzero-call-used-regs=3Dused-gpr", + "-Wimplicit-fallthrough=3D2", + "-Wold-style-declaration", + "-Wno-psabi", + "-Wshadow=3Dlocal", + "-c", + } + + # Remove + # - output of makefile rules (-MQ,-MF target); + # - output of object files (-o target); + # - excessive zero-initialization of block-scope variables + # (-ftrivial-auto-var-init=3Dzero); + # - and any optimization flags (-O). + for i, arg in reversed(list(enumerate(command))): + if arg in {"-MQ", "-o", "-MF"}: + del command[i : i + 2] + elif arg.startswith("-O") or arg in flags_to_remove: + del command[i] + + # Define a HELPER_TO_TCG macro for translation units wanting to + # conditionally include or exclude code during translation to TCG. + # Disable optimization (-O0) and make sure clang doesn't emit optnone + # attributes (-disable-O0-optnone) which inhibit further optimization. + # Optimization will be performed at a later stage in the helper-to-tcg + # pipeline. + command +=3D [ + "-S", + "-emit-llvm", + "-DHELPER_TO_TCG_IR_GEN", + "-O0", + "-g", + "-Xclang", + "-disable-O0-optnone", + ] + if output_path: + command +=3D ["-o", output_path] + + run_command(command) + + +def main(): + parser =3D argparse.ArgumentParser( + description=3D"Produce the LLVM IR of a given .c file." + ) + parser.add_argument( + "--compile-commands", required=3DTrue, help=3D"Path to compile_com= mands.json" + ) + parser.add_argument("--clang", default=3D"clang", help=3D"Path to clan= g.") + parser.add_argument("--llvm-link", default=3D"llvm-link", help=3D"Path= to llvm-link.") + parser.add_argument("-o", "--output", required=3DTrue, help=3D"Output = .ll file path") + parser.add_argument( + "--target-path", help=3D"Path to QEMU target dir. (e.q. target/i38= 6)" + ) + parser.add_argument("inputs", nargs=3D"+", help=3D".c file inputs") + args =3D parser.parse_args() + + outputs =3D [] + for input in args.inputs: + output =3D os.path.basename(input) + ".ll" + generate_llvm_ir( + args.compile_commands, args.clang, output, input, args.target_= path + ) + outputs.append(output) + + run_command([args.llvm_link] + outputs + ["-S", "-o", args.output]) + + +if __name__ =3D=3D "__main__": + sys.exit(main()) diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 8ab58adb39..97bce186fe 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -42,6 +42,14 @@ endif sources =3D [ ] =20 +clang =3D bindir / 'clang' +llvm_link =3D bindir / 'llvm-link' + +get_llvm_ir_cmd =3D [python, meson.current_source_dir() / 'get-llvm-ir.py', + '--compile-commands', 'compile_commands.json', + '--clang', clang, + '--llvm-link', llvm_link] + # NOTE: Add -Wno-template-id-cdtor for GCC versions >=3D 14. This warning= is # related to a change in the C++ standard in C++20, that also applies to C= ++14 # for some reason. See defect report DR2237 and commit --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380942; cv=none; d=zohomail.com; s=zohoarc; b=L5Uj+HHfDucRZflPhQ7N6tngCSwOjozrx6pbSkle5lg/W20ZiK3rktDQ0hn3+ALw0ilAfZ7pa5SO6CiU+5zrDlSS5hCkK1jcZ3vXbX7/LoAQ5Qr6tWQpwP/kxFI3Se8umlEpXnXx0Nx0iORMzmJIZ1hENRKAoWNk5J1kwf74FjY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380942; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=a1qsAGaR4LgJCtj8xxxYgcUmd5Ee5pQgbWSEUkovCOw=; b=BrE6rH46JUocXyGEB3Vd4jns82uUSyMeJ779SbC6QECOMh3xcGzjy6iqSHiKMHLP4hpmtfze0lnSKbtnPsGj12L4jxLlRFj3eSPg7xcNvr17f0y6Yy62Y6DzXXYZv6WE/+Zv28aGA7bA9c/B4y7Ls1bvNEQBlA1UXZkZ7mxzH70= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380942762358.05791720102945; Wed, 29 Jul 2026 20:09:02 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH5v-0001qx-3L; Wed, 29 Jul 2026 23:06:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5t-0001n4-8H for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:01 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5q-0002sX-Sr for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=a1qsAGaR4LgJCtj8xxxYgcUmd5Ee5pQgbWSEUkovCOw=; b=VpMiZYIdCe4EFW5 DCugNvwK01PdWBzw8Kqb0YDsNUo8BlQ9769ikHtMzQYgqmcleG9YOlxE+fOKIIjhUYNhQvmQ7ExVp VGMCBDDUwWZhlp3Td+6sKweqi7FbyKJkLT1koPrQ0z8a893+7gItlJc1S5Gp177hHPsqZYUzyWpXF HA=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 08/50] helper-to-tcg: Handle LLVM version compatibility Date: Thu, 30 Jul 2026 05:09:42 +0200 Message-ID: <20260730031025.12926-9-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380943450158500 Content-Type: text/plain; charset="utf-8" Adds a translation unit with the sole purpose of handling inter-LLVM code changes. Instead of littering the code with #ifdefs, most of them will be limited to LlvmCompat.[cpp|hpp] and a saner compat::*() function is exposed in its place. Signed-off-by: Anton Johansson --- .../helper-to-tcg/include/LlvmCompat.hpp | 124 ++++++++++++++++++ subprojects/helper-to-tcg/meson.build | 1 + subprojects/helper-to-tcg/src/LlvmCompat.cpp | 89 +++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 subprojects/helper-to-tcg/include/LlvmCompat.hpp create mode 100644 subprojects/helper-to-tcg/src/LlvmCompat.cpp diff --git a/subprojects/helper-to-tcg/include/LlvmCompat.hpp b/subprojects= /helper-to-tcg/include/LlvmCompat.hpp new file mode 100644 index 0000000000..78822ca87b --- /dev/null +++ b/subprojects/helper-to-tcg/include/LlvmCompat.hpp @@ -0,0 +1,124 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +// +// The purpose of this file is to both collect and hide most api-specific +// changes of LLVM [10,14]. Hopefully making it easier to keep track of the +// changes necessary to support our targeted versions. +// +// Note some #ifdefs still remain throughout the codebase for larger codeb= locks +// that are specific enough such that pulling them here would be more cumb= ersome +// than it's worth. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace compat { + +constexpr auto OpenFlags =3D llvm::sys::fs::OF_TextWithCRLF; + +using OptimizationLevel =3D llvm::OptimizationLevel; + +constexpr auto LTOPhase =3D llvm::ThinOrFullLTOPhase::None; + +inline llvm::PassBuilder createPassBuilder(llvm::TargetMachine *TM, + llvm::PipelineTuningOptions &PT= O) { +#if LLVM_VERSION_MAJOR >=3D 16 + return llvm::PassBuilder(TM, PTO, std::nullopt); +#else + return llvm::PassBuilder(TM, PTO, llvm::None); +#endif +} + +// LLVM 16 changes the getFixedSize() -> getFixedValue() +size_t getTypeAllocSize(const llvm::DataLayout &DL, llvm::Type *Ty); + +// These rely on string comparison with QEMU names using StringRef::starts= with, +// which changed to StringRef::starts_with in LLVM 18. +bool isFunctionQemuHelper(llvm::StringRef Name); +bool isFunctionQemuLoadStore(llvm::StringRef Name); + +// LLVM 21 moved to initializing a TargetTransformInfo via unique_ptr, +// instead of by value. +template +auto makeTTI(llvm::TargetMachine *TM, const llvm::Function &F) { + // Use explicit TargetTransformInfo() contructor +#if LLVM_VERSION_MAJOR >=3D 21 + return llvm::TargetTransformInfo(std::make_unique(TM, F)); +#else + return llvm::TargetTransformInfo(T(TM, F)); +#endif +} + +// Note, since constexpr auto is used to alias a function, default +// arguments won't work. +// +// LLVM 20 deprecated getDeclaration() in favour of getOrInsertDeclaration= () +namespace Intrinsic { +#if LLVM_VERSION_MAJOR >=3D 20 +constexpr auto getOrInsertDeclaration =3D llvm::Intrinsic::getOrInsertDecl= aration; +#else +constexpr auto getOrInsertDeclaration =3D llvm::Intrinsic::getDeclaration; +#endif +} // namespace Intrinsic + +// Wrapper to convert Function- to Module analysis manager +template +inline const typename T::Result * +getModuleAnalysisManagerProxyResult(llvm::FunctionAnalysisManager &FAM, + llvm::Function &F) { + auto &MAMProxy =3D FAM.getResult(F); + return MAMProxy.getCachedResult(*F.getParent()); +} + +llvm::TargetMachine *getTargetMachine(llvm::Triple &TheTriple); + +// +// LLVM 11 and below does not define the UnifyFunctionExitNodes pass +// for the new pass manager. Copy over the definition and use it for +// 11 and below. +// +using llvm::UnifyFunctionExitNodesPass; + +inline uint32_t getVectorElementCount(const llvm::VectorType *VecTy) { + auto ElementCount =3D VecTy->getElementCount(); + return ElementCount.getFixedValue(); +} + +// +// PatternMatch +// + +#define compat_m_InsertElt llvm::PatternMatch::m_InsertElt +#define compat_m_Shuffle llvm::PatternMatch::m_Shuffle +#define compat_m_ZeroMask llvm::PatternMatch::m_ZeroMask + +} // namespace compat diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 97bce186fe..965014c988 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -40,6 +40,7 @@ if version_major < 10 or version_major > 21 endif =20 sources =3D [ + 'src/LlvmCompat.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/LlvmCompat.cpp b/subprojects/hel= per-to-tcg/src/LlvmCompat.cpp new file mode 100644 index 0000000000..3a1995391c --- /dev/null +++ b/subprojects/helper-to-tcg/src/LlvmCompat.cpp @@ -0,0 +1,89 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "LlvmCompat.hpp" + +#include +#include + +#include + +// Static variables required by LLVM +// +// Defining RegisterCodeGenFlags with static duration registers extra +// codegen commandline flags for specifying the target arch. +static llvm::codegen::RegisterCodeGenFlags CGF; +static llvm::ExitOnError ExitOnErr; + +namespace compat { + +using namespace llvm; + +size_t getTypeAllocSize(const llvm::DataLayout &DL, llvm::Type *Ty) { +#if LLVM_VERSION_MAJOR >=3D 16 + return DL.getTypeAllocSize(Ty).getFixedValue(); +#else + return DL.getTypeAllocSize(Ty).getFixedSize(); +#endif +} + +bool isFunctionQemuHelper(StringRef Name) { +#if LLVM_VERSION_MAJOR >=3D 18 + return Name.starts_with("helper_"); +#else + return Name.startswith("helper_"); +#endif +} + +bool isFunctionQemuLoadStore(StringRef Name) { +#if LLVM_VERSION_MAJOR >=3D 18 + return Name.starts_with("cpu_ld") or Name.starts_with("cpu_st"); +#else + return Name.startswith("cpu_ld") or Name.startswith("cpu_st"); +#endif +} + +llvm::TargetMachine *getTargetMachine(llvm::Triple &TheTriple) { + const TargetOptions Options{}; + std::string Error; + const Target *TheTarget =3D llvm::TargetRegistry::lookupTarget( + llvm::codegen::getMArch(), TheTriple, Error); + // Some modules don't specify a triple, and this is okay. + if (!TheTarget) { + return nullptr; + } + +#if LLVM_VERSION_MAJOR >=3D 18 + auto Level =3D llvm::CodeGenOptLevel::Aggressive; +#else + auto Level =3D llvm::CodeGenOpt::Aggressive; +#endif + +#if LLVM_VERSION_MAJOR >=3D 21 + return TheTarget->createTargetMachine( + llvm::Triple(TheTriple.getTriple()), llvm::codegen::getCPUStr(), + llvm::codegen::getFeaturesStr(), Options, + llvm::codegen::getExplicitRelocModel(), + llvm::codegen::getExplicitCodeModel(), Level); +#else + return TheTarget->createTargetMachine( + TheTriple.getTriple(), llvm::codegen::getCPUStr(), + llvm::codegen::getFeaturesStr(), Options, {}, {}, Level); +#endif +} + +} // namespace compat --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380861; cv=none; d=zohomail.com; s=zohoarc; b=ZeSswfYh9ycqk+G1YS8fk1X2zH581ZbAadCNIpxlVf3qyC6ow2FUFC/OpKvwDSkjgwmNHpuUJrq3zVzjvwXLQtkgM8FzWOa1oRirCMp24GtY811HXQb6TY8lCXIjpLzKv2s4pa5JzmeAxbQ8+BFgerkU2FdpQLhJrx4WiCsYXfg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380861; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=ih5zg/uLk39Z71+sgYtKvzrNyD7K2CngOA6d/ur0vuc=; b=aTcHkNhfoa3esrgSQnjR6fzTJOSlItNkMONHPnaW9BKN5G+6UIFGGwvU3PaE6kQR6yUXzcqccQ1xjjMwEIgsEeIofR8SAVFi4YgAz2x9UNEx12YHnE1Kv3pHnEolVNlRgdCfl2sSsji320miMxGBOwK2LOrz7mdU5t1XwNfImpw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380861957296.1161173599239; Wed, 29 Jul 2026 20:07:41 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH5v-0001rd-Ut; Wed, 29 Jul 2026 23:06:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5u-0001px-Ou for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:02 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5s-0002t7-9F for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=ih5zg/uLk39Z71+sgYtKvzrNyD7K2CngOA6d/ur0vuc=; b=OO2n4nh5zH2UrLM DVIwuFs7fwcV3JHzN1ItE7pSxUUhmc4cbZa5SyIGZTolm+4hgVi6zZn8pJqhU4mJ3+wRMdvnOkSqW Nh1CiVzEXNjclBXhzeFaizOQrgQCCfrJWd43s322yjtQayRmPO3NcXckOeLMZSRCVTt5QDqrQkDU0 v4=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 09/50] helper-to-tcg: Introduce custom LLVM pipeline Date: Thu, 30 Jul 2026 05:09:43 +0200 Message-ID: <20260730031025.12926-10-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380863117158500 Content-Type: text/plain; charset="utf-8" Adds a custom pipeline, similar to LLVM opt, with the goal of taking an input LLVM IR module to an equivalent output .c file implementing functions in TCG. Initial LLVM boilerplate is added up until the creation of a ModulePassManager. A custom target derived from x64 is added, to ensure consistent behaviour across different hosts. Signed-off-by: Anton Johansson --- .../helper-to-tcg/include/CmdLineOptions.hpp | 23 +++ subprojects/helper-to-tcg/meson.build | 1 + subprojects/helper-to-tcg/src/Pipeline.cpp | 146 ++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 subprojects/helper-to-tcg/include/CmdLineOptions.hpp create mode 100644 subprojects/helper-to-tcg/src/Pipeline.cpp diff --git a/subprojects/helper-to-tcg/include/CmdLineOptions.hpp b/subproj= ects/helper-to-tcg/include/CmdLineOptions.hpp new file mode 100644 index 0000000000..93706b78c5 --- /dev/null +++ b/subprojects/helper-to-tcg/include/CmdLineOptions.hpp @@ -0,0 +1,23 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include + +// Options for pipeline +extern llvm::cl::list InputFiles; diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 965014c988..ca46578cb3 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -41,6 +41,7 @@ endif =20 sources =3D [ 'src/LlvmCompat.cpp', + 'src/Pipeline.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp new file mode 100644 index 0000000000..f36f447fd2 --- /dev/null +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -0,0 +1,146 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "CmdLineOptions.hpp" +#include "LlvmCompat.hpp" + +#if LLVM_VERSION_MAJOR =3D=3D 15 +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +cl::OptionCategory Cat("helper-to-tcg Options"); + +// Options for pipeline +cl::opt InputFile(cl::Positional, cl::desc("[input LLVM modul= e]"), + cl::cat(Cat)); + +// Define a TargetTransformInfo (TTI) subclass, this allows for overriding +// common per-llvm-target information expected by other LLVM passes, such +// as the width of the largest scalar/vector registers. Needed for consis= tent +// behaviour across different hosts. +class TcgTTI : public BasicTTIImplBase { + friend class BasicTTIImplBase; + + // We need to provide ST, TLI, getST(), getTLI() + const TargetSubtargetInfo *ST; + const TargetLoweringBase *TLI; + + const TargetSubtargetInfo *getST() const { return ST; } + const TargetLoweringBase *getTLI() const { return TLI; } + + public: + // Initialize ST and TLI from the target machine, e.g. if we're + // targeting x86 we'll get the Subtarget and TargetLowering to + // match that architechture. + TcgTTI(TargetMachine *TM, Function const &F) + : BasicTTIImplBase(TM, F.getParent()->getDataLayout()), + ST(TM->getSubtargetImpl(F)), TLI(ST->getTargetLowering()) {} + + TypeSize getRegisterBitWidth(TargetTransformInfo::RegisterKind K) cons= t { + switch (K) { + case TargetTransformInfo::RGK_Scalar: + // We pretend we always support 64-bit registers + return TypeSize::getFixed(64); + case TargetTransformInfo::RGK_FixedWidthVector: + // We pretend we always support 2048-bit vector registers + return TypeSize::getFixed(2048); + case TargetTransformInfo::RGK_ScalableVector: + return TypeSize::getScalable(0); + default: + abort(); + } + } +}; + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + cl::HideUnrelatedOptions(Cat); + + InitializeAllTargets(); + InitializeAllTargetMCs(); + PassRegistry &Registry =3D *PassRegistry::getPassRegistry(); + initializeCore(Registry); + initializeScalarOpts(Registry); + initializeVectorization(Registry); + initializeAnalysis(Registry); + initializeTransformUtils(Registry); + initializeInstCombine(Registry); + initializeTarget(Registry); + + cl::ParseCommandLineOptions(argc, argv); + + LLVMContext Context; + + SMDiagnostic Err; + std::unique_ptr M =3D parseIRFile(InputFile, Err, Context); + + // Create a new TargetMachine to represent a TCG target, + // we use x86_64 as a base and derive from that using a + // TargetTransformInfo to provide allowed scalar and vector + // register sizes. + Triple ModuleTriple("x86_64-pc-unknown"); + assert(ModuleTriple.getArch()); + TargetMachine *TM =3D compat::getTargetMachine(ModuleTriple); + + PipelineTuningOptions PTO; + PassBuilder PB =3D compat::createPassBuilder(TM, PTO); + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + + // Register our TargetIrAnalysis pass using our own TTI + FAM.registerPass([&] { + return TargetIRAnalysis( + [&TM](const Function &F) -> TargetIRAnalysis::Result { + return compat::makeTTI(TM, F); + }); + }); + + // Register other default LLVM Analyses + PB.registerFunctionAnalyses(FAM); + PB.registerModuleAnalyses(MAM); + PB.registerLoopAnalyses(LAM); + PB.registerCGSCCAnalyses(CGAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + ModulePassManager MPM; + + return 0; +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380954; cv=none; d=zohomail.com; s=zohoarc; b=oLUYLER95R0oj4y18kQ2Vb2PzSqMOgsbmGpPGxYva3EVfftwhzMX7uvyU875qgqb3y5ojxuFKQ4RDxHL1Dw+0DjoBAi8Jw5JOrERmrzdxO9N8GgEGkcSXM5WD/IhmddRB2rESdI4v2oWDDepnH1LcELXFPCrqsdOvJ1apDA2wV4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380954; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=VWdBD/ZkDSAkkTaoQpaJfwXB2GjEbhoi3wL1Dg6e5rg=; b=cT4vYLXSIzmp6KLBcgkp3yp+OCnbxNnXZznCX7bHt6lmOamCvy48mog6lSTQIavwyikYCaeZShjlHpxACY9KnTMj3gtoGhNXyEgqTrT+37HV4kmVevFeV1ksUSWazIK+F8Tde/qpRO+OL2Qb63LATZkVM2yPBILbNxGQmiKbftw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380954374872.2940790555487; Wed, 29 Jul 2026 20:09:14 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH5x-0001sD-IM; Wed, 29 Jul 2026 23:06:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5w-0001rf-5k for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:04 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5u-0002tN-MG for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:03 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=VWdBD/ZkDSAkkTaoQpaJfwXB2GjEbhoi3wL1Dg6e5rg=; b=KW22BG1RmFGHJcR W3fgwqUJpKeUMYDIbFmeKF7GhkWzoBzORVBGv8+Dypa+iOZzKgf8pzwAWNQPdhAH9PjbN/V34Zsu/ J09fvKlp9CA+T/PYtoX7EaeRZ7TW1KkzCv8Vmv6hMmND0UDu9PYFc/ZGHOyKzu3T4qXwm3E7NnrZO Jg=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 10/50] helper-to-tcg: Add pipeline --debug and --debug-only Date: Thu, 30 Jul 2026 05:09:44 +0200 Message-ID: <20260730031025.12926-11-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380955566158500 Content-Type: text/plain; charset="utf-8" These options are normally added by LLVM, however since we want a minimal set of options in --help we have to readd them ourselves. Signed-off-by: Anton Johansson --- subprojects/helper-to-tcg/src/Pipeline.cpp | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp index f36f447fd2..4b9523ad6f 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -37,11 +37,14 @@ #include #include #include +#include #include #include #include #include =20 +#define DEBUG_TYPE "pipeline" + using namespace llvm; =20 cl::OptionCategory Cat("helper-to-tcg Options"); @@ -50,6 +53,16 @@ cl::OptionCategory Cat("helper-to-tcg Options"); cl::opt InputFile(cl::Positional, cl::desc("[input LLVM modul= e]"), cl::cat(Cat)); =20 +// Debug options +#ifndef NDEBUG +static cl::opt Debug("debug", cl::desc("Enable debug logging (slow)"= ), + cl::init(false), cl::cat(Cat)); +static cl::opt + DebugOnly("debug-only", + cl::desc("Enable debug logging for a specific pass"), + cl::init(""), cl::cat(Cat)); +#endif + // Define a TargetTransformInfo (TTI) subclass, this allows for overriding // common per-llvm-target information expected by other LLVM passes, such // as the width of the largest scalar/vector registers. Needed for consis= tent @@ -105,8 +118,18 @@ int main(int argc, char **argv) { =20 cl::ParseCommandLineOptions(argc, argv); =20 - LLVMContext Context; + // Enable debug logging, -debug and -debug-only are normally provided = by + // LLVMs default debug options, but since we want to hide most default + // options and keep them visible during a debug build it's easiest to = add + // them back manually +#ifndef NDEBUG + DebugFlag =3D Debug; + if (!DebugOnly.empty()) { + setCurrentDebugType(DebugOnly.c_str()); + } +#endif =20 + LLVMContext Context; SMDiagnostic Err; std::unique_ptr M =3D parseIRFile(InputFile, Err, Context); =20 --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380786; cv=none; d=zohomail.com; s=zohoarc; b=V54ocySkwkqP1ww0qaL23kytxPSN92fHcOLPVEEOMEORIhITmAd9N1WEmTqH9Jbs6j2QzR/DRQrO25QSEBTyTf9oEuhRG+WYxjoPzHv5o1+EdGcazRqDq4B0PCTDo+zsE5BLHfdu/EDempDxl8v3sbtm7bxg/Q8w5N/mWoS6GWQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380786; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=3WWfX55JwVeFWu5Dl5xBCgAYmh0Nf5OcQb4Hh4OkbpA=; b=nJ/fwCa3fX6opGFxd+VWIiLfoSlTrPZuJw6B5LkJLBjxCFZHTpVS4/2rzl96SdpB9753zQQB1VkyU7HLpC0o5r+VfiEeVjlP20OyXJM35OPB9lZ8FxmN4XidNIzf2cTNmVtNCupV/j0oh18q8U6wFny6yFjb0IG0TzPRG6mlSv0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380785981967.4472196532688; Wed, 29 Jul 2026 20:06:25 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH60-0001sz-8u; Wed, 29 Jul 2026 23:06:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5y-0001sZ-NZ for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:06 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH5x-0002tm-6v for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=3WWfX55JwVeFWu5Dl5xBCgAYmh0Nf5OcQb4Hh4OkbpA=; b=hRwe9GdoiysiGaI Xj6C7rf7VKJ33WPzzQZLsNahTg9rxInLJ33XNKi9fDCSl10zEuKGTNpQl9DXMwJy7DGF0OHYYNIrW huAYwYJ/DbFKdOtit9D4CpDP0IqVFA6Ic4nitan+pIx1TjSKS39mYfei9K0nxYL02eyTxnDtvmgl3 F8=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 11/50] helper-to-tcg: Add simple error creation helper Date: Thu, 30 Jul 2026 05:09:45 +0200 Message-ID: <20260730031025.12926-12-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380788775158500 Content-Type: text/plain; charset="utf-8" Simple function for creating Expected<> with nice error messages. Signed-off-by: Anton Johansson --- subprojects/helper-to-tcg/include/Error.hpp | 38 +++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 subprojects/helper-to-tcg/include/Error.hpp diff --git a/subprojects/helper-to-tcg/include/Error.hpp b/subprojects/help= er-to-tcg/include/Error.hpp new file mode 100644 index 0000000000..835610d83e --- /dev/null +++ b/subprojects/helper-to-tcg/include/Error.hpp @@ -0,0 +1,38 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include +#include + +inline llvm::Error mkError(const llvm::StringRef Msg) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), Msg); +} + +// TODO: Usage of `mkError()` and `dbgs()` for serializing `Value`s is +// __really__ slow, and should only occur for error reporting. +// `ModuleSlotTracker` could be used which would speed up repeated seriali= zation +// of a `Value`. +inline llvm::Error mkError(const llvm::StringRef Msg, const llvm::Value *V= ) { + std::string Str; + llvm::raw_string_ostream Stream(Str); + Stream << Msg; + Stream << *V; + Stream.flush(); + return llvm::createStringError(llvm::inconvertibleErrorCode(), Str); +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380970; cv=none; d=zohomail.com; s=zohoarc; b=fHGCCfiTA0KfrXULCO7+yRsypJHw1yd5eYOHc5DbR87/zRIDxmnemkkS9VYGl8BGyLosTGHtUBB/FOTFEVWlatdFEVdagPuxnPT54wkc2On6lwcEpZyrcZXT8VpG7CxJXCyYh9Y628xLctx89ecVUCdYZYc1UnMUrXdiy+oNeaw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380970; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=WxHUNRyY9SjQyZWdhZJJM6dALnjqTd/WEb4Rj+WgVnY=; b=Y+6w+7cWwlxTRETvC96+oEiCy8sKaxPdNehpBaRMOAyE4z628NNJq4T55pvnRE7EBwIfbo1wMhMvszjjGWzhwvVXojFc6Xz6MLmQPCmq/NRZAz8JSurgg1S7nypC1nuxQN3LTynTfmUhIxZwsgtFtzwaSNjTqqCQLtzDKu1uEnA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380970324875.3363867487507; Wed, 29 Jul 2026 20:09:30 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6D-0001uY-4d; Wed, 29 Jul 2026 23:06:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6B-0001u4-P4 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:19 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6A-0002tz-02 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:19 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=WxHUNRyY9SjQyZWdhZJJM6dALnjqTd/WEb4Rj+WgVnY=; b=qv6/Z9118cdg3zw 1qs6OjtD2xZWEuqofdAXSJKawyBYqb4l0JxYkafKDgkJiDfGgSjK85yWKDZVLd7IFed8iCo6kUdU7 0OmfWQgv/gfvP2LfBXyPtuoKN9oRMy8ls0VpEHn+B0CwPSJOE/zty2hv38CCCShG2Tswm1ciqlzQV i4=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 12/50] helper-to-tcg: Introduce PrepareForOptPass Date: Thu, 30 Jul 2026 05:09:46 +0200 Message-ID: <20260730031025.12926-13-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380971495158500 Content-Type: text/plain; charset="utf-8" Adds a new LLVM pass that runs early in the pipeline with the goal of preparing the input module for optimization by doing some early culling of functions and information gathering. This commits sets up a new LLVM pass over the IR module and runs it from the pipeline. Signed-off-by: Anton Johansson --- .../include/PrepareForOptPass.hpp | 34 +++++++++++++++++++ subprojects/helper-to-tcg/meson.build | 1 + subprojects/helper-to-tcg/src/Pipeline.cpp | 27 +++++++++++++++ .../PrepareForOptPass/PrepareForOptPass.cpp | 29 ++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 subprojects/helper-to-tcg/include/PrepareForOptPass.hpp create mode 100644 subprojects/helper-to-tcg/src/PrepareForOptPass/Prepare= ForOptPass.cpp diff --git a/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp b/subp= rojects/helper-to-tcg/include/PrepareForOptPass.hpp new file mode 100644 index 0000000000..2b3694c536 --- /dev/null +++ b/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp @@ -0,0 +1,34 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include + +// +// PrepareForOptPass +// +// Pass that performs either early information collection or basic culling= of +// the input module. simplify the module, or to allow for further optimiza= tion. +// + +class PrepareForOptPass : public llvm::PassInfoMixin { +public: + PrepareForOptPass() {} + llvm::PreservedAnalyses run(llvm::Module &M, + llvm::ModuleAnalysisManager &MAM); +}; diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index ca46578cb3..4fd0ddb778 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -42,6 +42,7 @@ endif sources =3D [ 'src/LlvmCompat.cpp', 'src/Pipeline.cpp', + 'src/PrepareForOptPass/PrepareForOptPass.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp index 4b9523ad6f..59de572bf6 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -17,6 +17,7 @@ =20 #include "CmdLineOptions.hpp" #include "LlvmCompat.hpp" +#include "PrepareForOptPass.hpp" =20 #if LLVM_VERSION_MAJOR =3D=3D 15 #include @@ -42,6 +43,7 @@ #include #include #include +#include =20 #define DEBUG_TYPE "pipeline" =20 @@ -165,5 +167,30 @@ int main(int argc, char **argv) { =20 ModulePassManager MPM; =20 + // + // Start by Filtering out functions we don't want to translate, + // following by a pass that removes `noinline`s that are inserted + // by clang on -O0. We finally run a UnifyExitNodesPass to make sure + // the helpers we parse only has a single exit. + // + + { + FunctionPassManager FPM; +#if LLVM_VERSION_MAJOR >=3D 16 + FPM.addPass(SROAPass(SROAOptions::ModifyCFG)); +#else + FPM.addPass(SROAPass()); +#endif + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } + + MPM.addPass(PrepareForOptPass()); + + { + FunctionPassManager FPM; + FPM.addPass(compat::UnifyFunctionExitNodesPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } + return 0; } diff --git a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass= .cpp new file mode 100644 index 0000000000..4a7e82b7bd --- /dev/null +++ b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp @@ -0,0 +1,29 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "PrepareForOptPass.h" + +#include + +#define DEBUG_TYPE "prepare-for-opt" + +using namespace llvm; + +PreservedAnalyses PrepareForOptPass::run(Module &M, + ModuleAnalysisManager &MAM) { + return PreservedAnalyses::none(); +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380788; cv=none; d=zohomail.com; s=zohoarc; b=TOesFv4M+wMVoJeAjQ4R6g860KegOqwBuc7gxxf+ST9WYWgvRSw72RI5wvw7tW+r+7TtxD7jzF+thRl2frQIxXlY1/i/zhzSrVlQRXYCDU9RwrrGcWI9NAQZt5T5If3Fan6facY6pvUrzXxzCrCNZNg0+oW0S1onSN6cFQ7iCfY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380788; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=uLqtHJz2VyYpgaV81tSrDoiR9LgLkEh8YUj6ngUq2x0=; b=eSe2XOJbUciV8Rzn6nJwyxOjQCK2Jy6SKrR1aXi8dhxJ2E38rBdWWFHb3orIGgoDFji65SbUlf0KY7wBTKiG3JUDTy5PR3quhyi+4L5Lm5oTgPurZBgU2qNSTPnSYQExYAHr+kmYVpVWxGtpSNq5sCIrRGMO/cF2y6StaiCAABQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380788802603.7473572839086; Wed, 29 Jul 2026 20:06:28 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6E-0001um-Ek; Wed, 29 Jul 2026 23:06:22 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6D-0001ua-92 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:21 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6B-0002u4-Nv for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=uLqtHJz2VyYpgaV81tSrDoiR9LgLkEh8YUj6ngUq2x0=; b=Cb/X9U6/3LJ98P4 zM918unr9/wVaWLsLGE4caSzrWNqlftH2N9FVgcTmJbN2qA6XyM+prGUWzQRV3zghBmliW6l9lE3r WHfMeVNef6xFoC45os+k84xpw56yp6Sh3b9atkv4GTlbQuv1baf4OHR3wpwXFcTRMpwRqOc2oqBQC mc=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 13/50] helper-to-tcg: PrepareForOptPass, demangle function names Date: Thu, 30 Jul 2026 05:09:47 +0200 Message-ID: <20260730031025.12926-14-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380790784158500 Content-Type: text/plain; charset="utf-8" Since input LLVM IR might come from languages which mangle function names, e.g. C++, take extra care to demangle all function names and save them on the side for future lookup. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- .../PrepareForOptPass/PrepareForOptPass.cpp | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass= .cpp index 4a7e82b7bd..c15c0af6ea 100644 --- a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp @@ -15,15 +15,56 @@ // along with this program; if not, see . // =20 -#include "PrepareForOptPass.h" +#include "PrepareForOptPass.hpp" =20 +#include +#include +#include #include =20 #define DEBUG_TYPE "prepare-for-opt" =20 using namespace llvm; =20 +static void demangleFunctionNames(Module &M) { + StringSet DemangledNames; + for (Function &F : M) { + const std::string DemangledName =3D llvm::demangle(F.getName().str= ()); + if (DemangledName =3D=3D F.getName()) { + // Name not mangled + continue; + } + // The resulting demangled name might look something like + // + // namespace::subnamespace::function(...) + // + // Extract the function name and use this to replace mangled name.= If + // we previously encountered the same name, give up and leave the + // mangled name. + std::string FunctionName; + size_t Index =3D 0; + // Remove namespaces + Index =3D DemangledName.find_last_of(':'); + if (Index !=3D std::string::npos) { + FunctionName =3D DemangledName.substr(Index + 1); + } + // Remove arguments + Index =3D FunctionName.find_first_of('('); + if (Index !=3D std::string::npos) { + FunctionName =3D FunctionName.substr(0, Index); + } + + if (DemangledNames.contains(FunctionName)) { + continue; + } + DemangledNames.insert(FunctionName); + + F.setName(FunctionName); + } +} + PreservedAnalyses PrepareForOptPass::run(Module &M, ModuleAnalysisManager &MAM) { + demangleFunctionNames(M); return PreservedAnalyses::none(); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380815; cv=none; d=zohomail.com; s=zohoarc; b=D2iZwQH6H93y9I+e7heuZ8d/wipIr9j6dKXfAgilDmhI/hoooWQEhJ7tjQzFZ7OOnMowiLL1nBh2mjtSLrMULMAw/DhYZh5LgsYUbuKX/GDOmB9/jCgW7hFSGDiGzob0nRf67xY3ADYEBgdmnLpVjpOj3NNyzGXYDObSDEJuH/0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380815; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=0VLdaQBq584YS84hmcm+SAqGLpmZtRsRFoJoJ75Ckkk=; b=BGbSFc7VVHKK5ncY1R4WDWCCLftvdgN2o1pmDGAy/8uS48J5fVycPbSqa6P1285dtD9oIqv2cf+8glq4e9nJ8m5guZrkMQYuZ8ur2680C9fTptAlTs7tQYSJ8pVOG2Yq+iDcdfECMLp5uH5bz7vC4emwb7TLCfcRGSMhIjOb23I= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178538081559724.122032438924293; Wed, 29 Jul 2026 20:06:55 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6G-0001vU-JD; Wed, 29 Jul 2026 23:06:24 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6F-0001v9-60 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:23 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6C-0002uL-VP for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:22 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=0VLdaQBq584YS84hmcm+SAqGLpmZtRsRFoJoJ75Ckkk=; b=EkEsc82WVsngqCI QWwvnVZl4clft91iJGdBp55rKXIrBXxBMFdhsdLZICKsb7Qp93e/KXZwsZYTz8rmK6KV07etCOCIV t+c3IhIqO6uJls4zLRixYU5d6w/lA9Hf5q142nhHY037TmT5nLdepq5Rg5OwuAZwP3/C2aku96GjH A4=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 14/50] helper-to-tcg: PrepareForOptPass, map annotations Date: Thu, 30 Jul 2026 05:09:48 +0200 Message-ID: <20260730031025.12926-15-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380817208158500 Content-Type: text/plain; charset="utf-8" In the LLVM IR module, function annotations are stored in one big global array of strings. Traverse this array and parse the data into a format more useful for future passes. A map between Functions * and an `Annotations` structure is exposed. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- .../include/FunctionAnnotation.hpp | 104 ++++++++++++++++++ .../include/PrepareForOptPass.hpp | 7 +- subprojects/helper-to-tcg/src/Pipeline.cpp | 6 +- .../PrepareForOptPass/PrepareForOptPass.cpp | 94 ++++++++++++++++ 4 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 subprojects/helper-to-tcg/include/FunctionAnnotation.hpp diff --git a/subprojects/helper-to-tcg/include/FunctionAnnotation.hpp b/sub= projects/helper-to-tcg/include/FunctionAnnotation.hpp new file mode 100644 index 0000000000..398dd53ef5 --- /dev/null +++ b/subprojects/helper-to-tcg/include/FunctionAnnotation.hpp @@ -0,0 +1,104 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include +#include +#include +#include +#include + +namespace llvm { +class Function; +} + +// Different kind of function annotations which control the behaviour +// of helper-to-tcg. +enum class ArgumentAnnotation : uint8_t { + // Declares a list of arguments as immediates + Immediate =3D 1, + // Declares a list of arguments as vectors, represented by offsets into + // the CPU state + PtrToOffset =3D 2, +}; + +// Different kind of function annotations which control the behaviour +// of helper-to-tcg. +enum class FunctionAnnotation : uint8_t { + // Function should be translated + HelperToTcg =3D 1, + // Return value of function is an immediate + ReturnsImmediate =3D 2, +}; + +// Annotation data which may be attached to a function +class Annotations { + // 8-bit flag for each argument in a function, fields defined by + // `ArgumentAnnotions`. + llvm::SmallVector ArgumentAnnotations; + // Flag of function annotations, fields defined by `FunctionsAnnotatio= ns`. + uint8_t FunctionAnnotations =3D 0; + + public: + inline uint8_t getArgFlag(size_t Index) const { + if (Index >=3D ArgumentAnnotations.size()) { + return 0; + } + return ArgumentAnnotations[Index]; + } + + // Getters and setters for annotations flags. + + inline void set(FunctionAnnotation FA) { + FunctionAnnotations |=3D (uint8_t)FA; + } + + inline void set(size_t Index, ArgumentAnnotation AA) { + if (Index >=3D ArgumentAnnotations.size()) { + // Resizing will default initialize any new elements. + ArgumentAnnotations.resize(Index + 1); + } + ArgumentAnnotations[Index] |=3D (uint8_t)AA; + } + + inline bool isSet(FunctionAnnotation FA) const { + return (FunctionAnnotations & (uint8_t)FA) !=3D 0; + } + + inline bool isSet(size_t Index, ArgumentAnnotation AA) const { + uint8_t Flag =3D getArgFlag(Index); + return (Flag & (uint8_t)AA) !=3D 0; + } + + // Pretty printing debug information + inline void dump(llvm::raw_ostream &Out) const { + Out << "Annotations:\n"; + Out << " Function: " << llvm::format_hex(FunctionAnnotations, 4) + << "\n"; + for (size_t I =3D 0; I < ArgumentAnnotations.size(); ++I) { + const uint8_t Flag =3D ArgumentAnnotations[I]; + Out << " Argument[" << I << "]: " << llvm::format_hex(Flag, 4) + << "\n"; + } + } +}; + +// Mapping from functions to annotations, this is the main structure to be= used +// by other parts of the codebase when referencing annotations, filled out= by +// `PrepareForOptPass`. +using AnnotationMapTy =3D llvm::DenseMap; diff --git a/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp b/subp= rojects/helper-to-tcg/include/PrepareForOptPass.hpp index 2b3694c536..e007243578 100644 --- a/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp +++ b/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp @@ -17,6 +17,7 @@ =20 #pragma once =20 +#include "FunctionAnnotation.hpp" #include =20 // @@ -27,8 +28,12 @@ // =20 class PrepareForOptPass : public llvm::PassInfoMixin { + AnnotationMapTy &ResultAnnotations; public: - PrepareForOptPass() {} + PrepareForOptPass(AnnotationMapTy &ResultAnnotations) + : ResultAnnotations(ResultAnnotations) + { + } llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM); }; diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp index 59de572bf6..051611b0f3 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -184,7 +184,11 @@ int main(int argc, char **argv) { MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } =20 - MPM.addPass(PrepareForOptPass()); + // TODO: Get pass results via dependencies instead? Adds more boiler-p= late + // but is correlct in LLVM-terms. + + AnnotationMapTy Annotations; + MPM.addPass(PrepareForOptPass(Annotations)); =20 { FunctionPassManager FPM; diff --git a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass= .cpp index c15c0af6ea..1228ac952f 100644 --- a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp @@ -16,10 +16,15 @@ // =20 #include "PrepareForOptPass.hpp" +#include "Error.hpp" =20 #include #include #include +#include +#include +#include +#include #include =20 #define DEBUG_TYPE "prepare-for-opt" @@ -63,8 +68,97 @@ static void demangleFunctionNames(Module &M) { } } =20 +static Error parseAnnotationStr(Annotations &Ann, StringRef Str, + size_t NumArgs) { + Str =3D Str.trim(); + + // Function annotations + if (Str.consume_front("helper-to-tcg")) { + Ann.set(FunctionAnnotation::HelperToTcg); + return Error::success(); + } else if (Str.consume_front("returns-immediate")) { + Ann.set(FunctionAnnotation::ReturnsImmediate); + return Error::success(); + } + + // Argument annotations + ArgumentAnnotation AA; + if (Str.consume_front("immediate")) { + AA =3D ArgumentAnnotation::Immediate; + } else if (Str.consume_front("ptr-to-offset")) { + AA =3D ArgumentAnnotation::PtrToOffset; + } else { + return mkError("Unknown annotation"); + } + + // An argument annotation looks like + // + // "immediate: 0, 1, 2", + // + // parse the comma separated list of argument indices. + if (!Str.consume_front(":")) { + return mkError("Expected \":\""); + } + Str =3D Str.ltrim(' '); + do { + Str =3D Str.ltrim(' '); + size_t I =3D 0; + Str.consumeInteger(10, I); + if (I >=3D NumArgs) { + return mkError("Annotation has out of bounds argument index"); + } + Ann.set(I, AA); + } while (Str.consume_front(",")); + + return Error::success(); +} + +static void collectAnnotations(Module &M, AnnotationMapTy &ResultAnnotatio= ns) { + // cast over dyn_cast is being used here to + // assert that the structure of + // + // llvm.global.annotation + // + // is what we expect. + + GlobalVariable *GA =3D M.getGlobalVariable("llvm.global.annotations"); + if (!GA) { + return; + } + + // Get the metadata which is stored in the first op + auto *CA =3D cast(GA->getOperand(0)); + // Loop over metadata + for (Value *CAOp : CA->operands()) { + auto *Struct =3D cast(CAOp); + assert(Struct->getNumOperands() >=3D 2); + + Function *F =3D cast(Struct->getOperand(0)); + ConstantDataArray *AnnData =3D + cast(Struct->getOperand(1)->getOperand(0)); + + StringRef AnnStr =3D AnnData->getAsString(); + AnnStr =3D AnnStr.substr(0, AnnStr.size() - 1); + Annotations Ann =3D ResultAnnotations[F]; + if (auto Err =3D parseAnnotationStr(Ann, AnnStr, F->arg_size()); E= rr) { + errs() << "Failed to parse annotation: \"" << Err + << "\" for function " << F->getName() << "\n"; + continue; + } + ResultAnnotations[F] =3D Ann; + } + + LLVM_DEBUG({ + for (auto &P : ResultAnnotations) { + dbgs() << "Annotations for " << P.first->getName() << "\n"; + P.second.dump(dbgs()); + } + }); +} + PreservedAnalyses PrepareForOptPass::run(Module &M, ModuleAnalysisManager &MAM) { demangleFunctionNames(M); + collectAnnotations(M, ResultAnnotations); return PreservedAnalyses::none(); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380834; cv=none; d=zohomail.com; s=zohoarc; b=jxhomWep6ed/HvYlOp346OVpOx8UL/DDxm6qCq6UnAD6kiquA+KLYXpzXfux9M3vA8wu9/FZwCt4PpUeYe8RyrHLvIKQ7UoYHERr5fnp91XRJEo/9Fsq/CUkiciGYu/F286Bs/tPgzGonJaGUKETPpWxxK4/ctnhER2Lz1Xo6Tk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380834; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=4Tb5OFlgULwGrf63MK6aCoPzsp36GX++Y+VZoCigufE=; b=a9MWw+P0K+aZjnw/6t1tWK0n5YS0YX3MxLmz9tkMkTj+T3NgfOXNhIo94RFpRvq+0H8KtA04P2evAlzcTac5H4niF/kpOlYi/6A1Yuni/SwFduXEfsYeKCU3AzvUN/W3kaK2EbBW5inXJWh5YlSniL0XSTC9dOu9b8A2fPAsrGE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380834851286.11075802095047; Wed, 29 Jul 2026 20:07:14 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6J-00023H-AE; Wed, 29 Jul 2026 23:06:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6G-0001vI-9y for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:24 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6E-0002uV-K6 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=4Tb5OFlgULwGrf63MK6aCoPzsp36GX++Y+VZoCigufE=; b=sHgTzSofpdRh9/I 7Uepo9inz+AJOhRaLQVXtJ+s+8ftzzuxOUaEG9XI0g4jrGo1/2LvQFhbTStyx1b1NkZuMU4BmUib7 EseB7tNCVgcMzxXFt/P5qJp+ZenXa/6qpGnGf1UYBAQF6a3sF4wFf6KuEByXvKYBYTEVF/KY9Ws7C YA=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 15/50] helper-to-tcg: PrepareForOptPass, cull unused functions Date: Thu, 30 Jul 2026 05:09:49 +0200 Message-ID: <20260730031025.12926-16-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380837068158500 Content-Type: text/plain; charset="utf-8" Make an early pass over all functions in the input module and filter out functions with: 1. Invalid return type, or; 2. No helper-to-tcg annotation and not called by a function with such a annotation. A commandline option is also added to force translation of all functions starting with "helper_". Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- .../helper-to-tcg/include/CmdLineOptions.hpp | 2 + .../include/PrepareForOptPass.hpp | 7 +- subprojects/helper-to-tcg/src/Pipeline.cpp | 5 ++ .../PrepareForOptPass/PrepareForOptPass.cpp | 86 +++++++++++++++++++ 4 files changed, 96 insertions(+), 4 deletions(-) diff --git a/subprojects/helper-to-tcg/include/CmdLineOptions.hpp b/subproj= ects/helper-to-tcg/include/CmdLineOptions.hpp index 93706b78c5..ca1cb59835 100644 --- a/subprojects/helper-to-tcg/include/CmdLineOptions.hpp +++ b/subprojects/helper-to-tcg/include/CmdLineOptions.hpp @@ -21,3 +21,5 @@ =20 // Options for pipeline extern llvm::cl::list InputFiles; +// Options for PrepareForOptPass +extern llvm::cl::opt TranslateAllHelpers; diff --git a/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp b/subp= rojects/helper-to-tcg/include/PrepareForOptPass.hpp index e007243578..08ca9a43bb 100644 --- a/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp +++ b/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp @@ -29,11 +29,10 @@ =20 class PrepareForOptPass : public llvm::PassInfoMixin { AnnotationMapTy &ResultAnnotations; -public: + + public: PrepareForOptPass(AnnotationMapTy &ResultAnnotations) - : ResultAnnotations(ResultAnnotations) - { - } + : ResultAnnotations(ResultAnnotations) {} llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM); }; diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp index 051611b0f3..89637eaec6 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -65,6 +65,11 @@ static cl::opt cl::init(""), cl::cat(Cat)); #endif =20 +// Options for PrepareForOptPass +cl::opt TranslateAllHelpers( + "translate-all-helpers", cl::init(false), + cl::desc("Translate all functions starting with helper_*"), cl::cat(Ca= t)); + // Define a TargetTransformInfo (TTI) subclass, this allows for overriding // common per-llvm-target information expected by other LLVM passes, such // as the width of the largest scalar/vector registers. Needed for consis= tent diff --git a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass= .cpp index 1228ac952f..df6d9eeec8 100644 --- a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp @@ -16,17 +16,25 @@ // =20 #include "PrepareForOptPass.hpp" +#include "CmdLineOptions.hpp" #include "Error.hpp" +#include "FunctionAnnotation.hpp" +#include "LlvmCompat.hpp" =20 +#include #include #include #include #include #include #include +#include #include #include =20 +#include +#include + #define DEBUG_TYPE "prepare-for-opt" =20 using namespace llvm; @@ -156,9 +164,87 @@ static void collectAnnotations(Module &M, AnnotationMa= pTy &ResultAnnotations) { }); } =20 +inline bool hasValidReturnTy(const Module &M, const Function *F) { + Type *RetTy =3D F->getReturnType(); + return RetTy->isStructTy() || RetTy =3D=3D Type::getVoidTy(F->getConte= xt()) || + RetTy =3D=3D Type::getInt8Ty(M.getContext()) || + RetTy =3D=3D Type::getInt16Ty(M.getContext()) || + RetTy =3D=3D Type::getInt32Ty(M.getContext()) || + RetTy =3D=3D Type::getInt64Ty(M.getContext()); +} + +// Functions that should be removed: +// - No helper-to-tcg annotation (if TranslateAllHelpers =3D=3D false); +// - Invalid (non-integer/void) return type +static bool shouldRemoveFunction(const Module &M, const Function &F, + const AnnotationMapTy &AnnotationMap) { + if (F.isDeclaration()) { + return false; + } + + if (!hasValidReturnTy(M, &F)) { + return true; + } + + std::queue Worklist; + std::set Visited; + Worklist.push(&F); + while (!Worklist.empty()) { + const Function *F =3D Worklist.front(); + Worklist.pop(); + if (F->isDeclaration() or Visited.find(F) !=3D Visited.end()) { + continue; + } + Visited.insert(F); + + if (TranslateAllHelpers and + compat::isFunctionQemuHelper(F->getName())) { + // If --translate-all-helpers is provided and `F` starts with + // "helper_*", then don't skip it. + return false; + } else if (auto It =3D AnnotationMap.find(F); It !=3D AnnotationMa= p.end()) { + // Otherwise check "helper-to-tcg" annotation. + const Annotations &Ann =3D It->second; + if (Ann.isSet(FunctionAnnotation::HelperToTcg)) { + return false; + } + } + + // Push functions that call `F` to the worklist, this way we retain + // functions that are being called by functions with the "helper-t= o-tcg" + // annotation. + for (const User *U : F->users()) { + auto Call =3D dyn_cast(U); + if (!Call) { + continue; + } + const Function *ParentF =3D Call->getParent()->getParent(); + Worklist.push(ParentF); + } + } + + return true; +} + +static void cullUnusedFunctions(Module &M, AnnotationMapTy &Annotations) { + SmallPtrSet FunctionsToRemove; + for (auto &F : M) { + if (shouldRemoveFunction(M, F, Annotations)) { + FunctionsToRemove.insert(&F); + } + } + + for (Function *F : FunctionsToRemove) { + Annotations.erase(F); + F->setComdat(nullptr); + F->deleteBody(); + } +} + PreservedAnalyses PrepareForOptPass::run(Module &M, ModuleAnalysisManager &MAM) { demangleFunctionNames(M); collectAnnotations(M, ResultAnnotations); + cullUnusedFunctions(M, ResultAnnotations); return PreservedAnalyses::none(); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380954; cv=none; d=zohomail.com; s=zohoarc; b=HqaO9c0G38bFEWRHgfj5L/2t+ZtLowBLO26btkJLZrp0OklxRW3zvWdbFftwiUm3y9zZv37+ghbSYOW81x5WCSFc2DHdh1e8geM8+D8ekPtuLi2yc47WWmnNXzqMzpbK4qibE6fZpr+qdDwBy4Lm1xjqB3+U2wfXRoDXNfFrWNY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380954; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=hsaoQKX2Io4yup0KQwT6GIWwdj31O9PhAvSFRd7GxKo=; b=baa/Je5T/HtBlYVhOa6TquCIY3zgAfiXuHczWNXqCQC/GziglJvDvBwCfH4icPdfweq1exV0ktpkUjQinkpzDabqi41FJsxRILPUAAbotmV4PcozC/KHpWBdso2zBnUHCA3/13UQog41EAnZ6ILl3JZdA4KiqbGF7S3X8hKiTM4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380954416125.00533959533675; Wed, 29 Jul 2026 20:09:14 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6I-00022o-Na; Wed, 29 Jul 2026 23:06:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6H-00021K-Vw for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:25 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6G-0002ua-Hh for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:25 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=hsaoQKX2Io4yup0KQwT6GIWwdj31O9PhAvSFRd7GxKo=; b=wHq0FCZlaABjvMs v+iWzkcsif3fmqHzrRTwGsjaUb+iW+6K2CUh6qIR43cr2xs2kOv+5mjk9+NJIiVyXHMJy5Ixqu17F ph3SxEPNZ4iMFr8ar5hyJI3omhwNB6Ao7z2Qw6IRChdjzVZoyjOcXME1kLvY3NHbe+H7AwDrAle0x MY=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 16/50] helper-to-tcg: PrepareForOptPass, undef llvm.returnaddress Date: Thu, 30 Jul 2026 05:09:50 +0200 Message-ID: <20260730031025.12926-17-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380955575158500 Content-Type: text/plain; charset="utf-8" Convert llvm.returnaddress arguments to cpu_[ld|st]*() to undef, causing the LLVM optmizer to discard the intrinsics. Needed as llvm.returnadress is not representable in TCG, and usually results from usage of GETPC() in helper functions. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- .../PrepareForOptPass/PrepareForOptPass.cpp | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass= .cpp index df6d9eeec8..157f8cd05e 100644 --- a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include =20 @@ -241,10 +242,56 @@ static void cullUnusedFunctions(Module &M, Annotation= MapTy &Annotations) { } } =20 +struct RetAddrReplaceInfo { + User *Parent; + unsigned OpIndex; + Type *Ty; +}; + +static void replaceRetaddrWithUndef(Module &M) { + // Replace uses of llvm.returnaddress arguments to cpu_ld* w. undef, + // and let optimizations remove it. Needed as llvm.returnaddress is + // not reprensentable in TCG. + SmallVector UsesToReplace; + Function *Retaddr =3D compat::Intrinsic::getOrInsertDeclaration( + &M, Intrinsic::returnaddress, {}); + // Loop over all calls to llvm.returnaddress + for (auto *CallUser : Retaddr->users()) { + auto *Call =3D dyn_cast(CallUser); + if (!Call) { + continue; + } + for (auto *PtrToIntUser : Call->users()) { + auto *Cast =3D dyn_cast(PtrToIntUser); + if (!Cast) { + continue; + } + for (Use &U : Cast->uses()) { + auto *Call =3D dyn_cast(U.getUser()); + Function *F =3D Call->getCalledFunction(); + if (compat::isFunctionQemuLoadStore(F->getName())) { + UsesToReplace.push_back({ + .Parent =3D U.getUser(), + .OpIndex =3D U.getOperandNo(), + .Ty =3D U->getType(), + }); + } + } + } + } + + // Defer replacement to not invalidate iterators + for (RetAddrReplaceInfo &RI : UsesToReplace) { + auto *Undef =3D UndefValue::get(RI.Ty); + RI.Parent->setOperand(RI.OpIndex, Undef); + } +} + PreservedAnalyses PrepareForOptPass::run(Module &M, ModuleAnalysisManager &MAM) { demangleFunctionNames(M); collectAnnotations(M, ResultAnnotations); cullUnusedFunctions(M, ResultAnnotations); + replaceRetaddrWithUndef(M); return PreservedAnalyses::none(); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380863; cv=none; d=zohomail.com; s=zohoarc; b=Yx3+N+FZeC5DzWT562hGmogY4FoBnSaRFvNQXGU4NrrvqJZDhbJZ4iNQHaZyQAKCwkA3E4HYOL2l7oJMr4RWqtnoqN3xRaFL/5/rD0Cwecd+KRmQRa0YoT25T3Ch/L0yXbw83WtjTuisjYSqtBo8zHqLkWttnkHRZUSFxeWRYG8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380863; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=h2V30jBABELpm4aezoVHqDB1cyBgu+VsaPq9sIBFBWQ=; b=lpJpBMmbT0XsvrUZjIRH9h6x/nAmXR2iAbR11WeCggwFvr1NtC/ucUEndSafJlL6aFt5c7M7tmn3EG+Yjq1/ntv/T2fx57CEN1450OysyEPN7OjIhFQ/DvFfc0XpgeWu2W0Iq8dPiFDDdxgqSfIdWG/h/msABd377/lgXzq6f54= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178538086396561.24214124888988; Wed, 29 Jul 2026 20:07:43 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6L-00026v-5b; Wed, 29 Jul 2026 23:06:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6J-00023h-Pj for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:27 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6I-0002ue-Ef for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=h2V30jBABELpm4aezoVHqDB1cyBgu+VsaPq9sIBFBWQ=; b=Gi3Tu811BLodO68 sPTd2V08XeF0ACIiaGWJN7SUXcYfqlYBXOLAPxksFQgAqD5aY15FZIXfCz/23i1TWzFP0oBUqiPsn T9ibfTFeUrTQT7/NceeRrTnEzUCCFcn1TXJVPYlTO3oCtJsbrblTs4uf0MtC8QI+LH+UV/Vjl6kLr MA=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 17/50] helper-to-tcg: PrepareForOptPass, fixup inline attributes Date: Thu, 30 Jul 2026 05:09:51 +0200 Message-ID: <20260730031025.12926-18-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380865042158500 Content-Type: text/plain; charset="utf-8" When producing LLVM IR using clang -O0, a noinline attribute is added. Remove this attribute to not inhibit future optimization. Also try and force functions returning struct type to be inlined so they might be translated. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- .../src/PrepareForOptPass/PrepareForOptPass.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass= .cpp index 157f8cd05e..a7bee53582 100644 --- a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp @@ -32,6 +32,7 @@ #include #include #include +#include =20 #include #include @@ -293,5 +294,18 @@ PreservedAnalyses PrepareForOptPass::run(Module &M, collectAnnotations(M, ResultAnnotations); cullUnusedFunctions(M, ResultAnnotations); replaceRetaddrWithUndef(M); + // Remove noinline function attributes automatically added by -O0, add + // alwaysinline attribute to functions with a struct return value, the= se + // can not be translated to TCG currently and we rely on inlining to + // hopefully get rid of them. + for (Function &F : M) { + if (F.hasFnAttribute(Attribute::AttrKind::NoInline)) { + F.removeFnAttr(Attribute::AttrKind::NoInline); + } + if (F.getReturnType()->isStructTy()) { + F.addFnAttr(Attribute::AttrKind::AlwaysInline); + } + } + return PreservedAnalyses::none(); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380799; cv=none; d=zohomail.com; s=zohoarc; b=a5BSHOVjS3kJmt6Uj585ccVJf0xGPR5WB8Nnd0t04adFgj5jjnzHAybFBxDj125uG4gC+KOzhOMGeROt20qqwhiRAeicOufp0c1azxF6L7t9ZiG5xNed9pvD8RBJKcmabE/deONyfcXCWynyBSaZLXCZ14jZaMVKIunNK1oQc9k= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380799; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=eWZchuVqzSjR2V6QniOrNG+R+2Zn07uA9lVeEhjH+3o=; b=Y45G35Y/qPoj2GrSKZy5TXiO26Ijqct62+5lmf9wMxKqWIGYudMn0K9KCu2GZd5yjY4cbUfcNEMfzY0nvnZqcRJsQhliVtqrbA5sFdYCE7mA+NKbkmszTAPNbdvgs2oG9hEWobE/kEpvCUi6mSjsxhDdbz58wFl4n13e0IIOBrA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380799382576.3437183460604; Wed, 29 Jul 2026 20:06:39 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6N-00029Z-VP; Wed, 29 Jul 2026 23:06:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6M-00027f-Ms for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:30 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6K-0002um-Ic for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:30 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=eWZchuVqzSjR2V6QniOrNG+R+2Zn07uA9lVeEhjH+3o=; b=VDf4TL+DQY2z+n+ A9rj1NanJFEupDQUDidbO6b9jNNql6dfGX8gigqLCIynKnFDIRlO/LH5AFQLiFmqa4lE2jmofGp/m geLeGiiSZtlT/Jfb5IiKdujybOur3rwezDxbe9XwvSzckE8Qm5KCWzFxRD7cu1iFwiKqPT5GE2zjF pM=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 18/50] helper-to-tcg: PrepareForOptPass, collect debuginfo Date: Thu, 30 Jul 2026 05:09:52 +0200 Message-ID: <20260730031025.12926-19-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380801186158500 Content-Type: text/plain; charset="utf-8" Debug information is collected before any non-preserving optimization pass is ran. Currently, only variable definitions are parsed, mapping a Value * to a name and typename. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- .../helper-to-tcg/include/DebugInfo.hpp | 46 ++++++++++++++++ .../include/PrepareForOptPass.hpp | 10 ++-- subprojects/helper-to-tcg/src/Pipeline.cpp | 3 +- .../PrepareForOptPass/PrepareForOptPass.cpp | 52 +++++++++++++++++++ 4 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 subprojects/helper-to-tcg/include/DebugInfo.hpp diff --git a/subprojects/helper-to-tcg/include/DebugInfo.hpp b/subprojects/= helper-to-tcg/include/DebugInfo.hpp new file mode 100644 index 0000000000..27e545c6b7 --- /dev/null +++ b/subprojects/helper-to-tcg/include/DebugInfo.hpp @@ -0,0 +1,46 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include +#include + +namespace llvm { +class Value; +} + +// StringRefs will refer do debug metadata fields which have the same +// lifetime as the LLVMContext and survive accross optimizations and +// possible deletions of functions/variables. +struct DebugInfo { + llvm::StringRef VarName; + llvm::StringRef BaseTypeName; +}; + +using DebugInfoMapTy =3D llvm::ValueMap; + +// Helper to get the variable name from debug info associated with a parti= cular +// value, or default construct an empty name. +inline llvm::StringRef getDebugVarName(const DebugInfoMapTy &DM, + const llvm::Value *V) { + auto It =3D DM.find(V); + if (It !=3D DM.end()) { + return It->second.VarName; + } + return {}; +} diff --git a/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp b/subp= rojects/helper-to-tcg/include/PrepareForOptPass.hpp index 08ca9a43bb..43cf77190a 100644 --- a/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp +++ b/subprojects/helper-to-tcg/include/PrepareForOptPass.hpp @@ -17,6 +17,7 @@ =20 #pragma once =20 +#include "DebugInfo.hpp" #include "FunctionAnnotation.hpp" #include =20 @@ -29,10 +30,13 @@ =20 class PrepareForOptPass : public llvm::PassInfoMixin { AnnotationMapTy &ResultAnnotations; + DebugInfoMapTy &ResultDebugInfo; =20 - public: - PrepareForOptPass(AnnotationMapTy &ResultAnnotations) - : ResultAnnotations(ResultAnnotations) {} +public: + PrepareForOptPass(AnnotationMapTy &ResultAnnotations, + DebugInfoMapTy &ResultDebugInfo) + : ResultAnnotations(ResultAnnotations), + ResultDebugInfo(ResultDebugInfo) {} llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM); }; diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp index 89637eaec6..a11c5fd353 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -193,7 +193,8 @@ int main(int argc, char **argv) { // but is correlct in LLVM-terms. =20 AnnotationMapTy Annotations; - MPM.addPass(PrepareForOptPass(Annotations)); + DebugInfoMapTy DebugInfo; + MPM.addPass(PrepareForOptPass(Annotations, DebugInfo)); =20 { FunctionPassManager FPM; diff --git a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass= .cpp index a7bee53582..7a9b954d7c 100644 --- a/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForOptPass/PrepareForOptPass.cpp @@ -26,6 +26,9 @@ #include #include #include +#if LLVM_VERSION_MAJOR >=3D 19 +#include +#endif #include #include #include @@ -288,6 +291,53 @@ static void replaceRetaddrWithUndef(Module &M) { } } =20 +static void collectDebugInfo(Function &F, DebugInfoMapTy &ResultDebugInfo)= { + StringSet EncounteredNames; + for (auto &BB : F) { + for (Instruction &I : BB) { +#if LLVM_VERSION_MAJOR >=3D 19 + for (DbgVariableRecord &DVR : + filterDbgVars(I.getDbgRecordRange())) { + if (!DVR.isDbgValue()) { + continue; + } + StringRef BaseType{}; + StringRef VarName{}; + if (auto *Derived =3D + dyn_cast(DVR.getVariable()->getType= ())) { + BaseType =3D Derived->getBaseType()->getName(); + } + VarName =3D DVR.getVariable()->getName(); + if (ResultDebugInfo.find(DVR.getValue(0)) =3D=3D + ResultDebugInfo.end() and + !EncounteredNames.contains(VarName.data())) { + ResultDebugInfo[DVR.getValue(0)] =3D {VarName, BaseTyp= e}; + EncounteredNames.insert(VarName.data()); + } + } +#else + if (I.isDebugOrPseudoInst()) { + if (const auto *Dbg =3D dyn_cast(&I)) { + StringRef BaseType{}; + StringRef VarName{}; + if (auto *Derived =3D dyn_cast( + Dbg->getVariable()->getType())) { + BaseType =3D Derived->getBaseType()->getName(); + } + VarName =3D Dbg->getVariable()->getName(); + if (ResultDebugInfo.find(Dbg->getValue(0)) =3D=3D + ResultDebugInfo.end() and + !EncounteredNames.contains(VarName.data())) { + ResultDebugInfo[Dbg->getValue(0)] =3D {VarName, Ba= seType}; + EncounteredNames.insert(VarName.data()); + } + } + } +#endif + } + } +} + PreservedAnalyses PrepareForOptPass::run(Module &M, ModuleAnalysisManager &MAM) { demangleFunctionNames(M); @@ -305,6 +355,8 @@ PreservedAnalyses PrepareForOptPass::run(Module &M, if (F.getReturnType()->isStructTy()) { F.addFnAttr(Attribute::AttrKind::AlwaysInline); } + // Populate variable and type names for `Value`s from debug info. + collectDebugInfo(F, ResultDebugInfo); } =20 return PreservedAnalyses::none(); --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380799; cv=none; d=zohomail.com; s=zohoarc; b=SjNMUf6WAVE8Bxs3KiJmhQNb6ypM7EeSYIklc+ISBcU5QWhQauKKUQvFQMbG7j7zud0kd084SSH+WqGgB8Z08K3Cxik2uBJVmxrfZwVHw/z205UK9e2elhqG4HutIFMl6i8wePCtow9m8zY1VdV0P1u/z/s95invOH8pM0DrNno= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380799; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=FDOSgS+bZgQArjJ2BBtHNM566dmwqv7hIxTW5eKrOp8=; b=JiGXh6/x2h+BpT5pEpZ71616wuCBwkzOpiUrtVbDSIs1BTkx/GNHiyPNRrlCYMh4IAVMAke+C9vzL9Koaf67o3m0iT65vYd8iFZD/oGTrYMsiTzoQ249iswCl42kZ0vVK8LqGmrld/OW8wsycC7hXkTyT4w/O45DpUnnnZgVSyo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380799444462.95929268060934; Wed, 29 Jul 2026 20:06:39 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6P-0002B7-NC; Wed, 29 Jul 2026 23:06:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6P-0002Af-3g for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:33 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6N-0002uz-M1 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:32 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=FDOSgS+bZgQArjJ2BBtHNM566dmwqv7hIxTW5eKrOp8=; b=tnLsX/c4NJMnsBc SizuEbNXe4NUf++fwjIEOS6kxhoZVkNz6NrtjiOj0gz9IF7m6HY5CWuanT65Gvm6rRQAcIOdzlUds 3/i9DTYYdMdRvM8cSavzsEzlmt3aB2uwCbKMvBv5g/EaRzaPquKKVe+C5MucrGjuNdKOe9kqtzz3N 9A=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 19/50] helper-to-tcg: Pipeline, run optimization pass Date: Thu, 30 Jul 2026 05:09:53 +0200 Message-ID: <20260730031025.12926-20-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380801110158500 Content-Type: text/plain; charset="utf-8" Run a standard LLVM -Oz optimization pass, which makes up the bulk of optimizations in helper-to-tcg. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- subprojects/helper-to-tcg/src/Pipeline.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp index a11c5fd353..571276de24 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -202,5 +202,17 @@ int main(int argc, char **argv) { MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } =20 + // + // Run a -Oz optimization pass. In general -Oz will prefer loop + // vectorization over unrolling, as compared to -O3. In TCG, this + // translates to more utilization of gvec and possibly smaller TBs. + // + + // Optimization passes + MPM.addPass(PB.buildModuleSimplificationPipeline( + compat::OptimizationLevel::Oz, compat::LTOPhase)); + MPM.addPass( + PB.buildModuleOptimizationPipeline(compat::OptimizationLevel::Oz, = {})); + return 0; } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381005; cv=none; d=zohomail.com; s=zohoarc; b=e5S5YlxKdMGlOCpkCCff26WFK43R/kBJKOEqd7VfU37MGZ2y9vByZLj4p0HeVomCrNYorXQV4su6vRxnw+qCI9NCkpDjn8keeHawE8LYfeWmmb8DWs4fMoY9VmA+H/fIKEQF7lnUBSPDKyEQO8ihoMJNUFBoCkIFcIZe7v2R8QI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381005; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=BeEI6y8lmgRfNz8jcM/GqFuGbWTUQcV1eN2XjXkvmhs=; b=IqqfG7pR7edz0x5Xly3qBoKaUl5xqqmGURSBwAXDzXkMTa3x4BXlbvZ3m+xId0qHtcTb7sATXePjnhTDjCHvUPHlqa4QhJnCSRJ1nGr+LTQeeUrmaAgrIpS/yNwzO4yhX9cVLt8gqlw+/ppU8HwqJZsdU71b65j+scChUOl9AHQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381005411388.3297468698562; Wed, 29 Jul 2026 20:10:05 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6V-0002G1-4k; Wed, 29 Jul 2026 23:06:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6T-0002CQ-57 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:37 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6Q-0002vI-Bu for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:36 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=BeEI6y8lmgRfNz8jcM/GqFuGbWTUQcV1eN2XjXkvmhs=; b=dKlMSvmVmOpsTNk bITE1oYEOub0X4pVwsfAnRpAuYtR2EWL7awlDE5kdsl5zv+zEiPZEmFjAUX4157Yru34MCu/uiZNd BuZGTya2h9bgl7plIy6m4Ig4WG427tbU+yRkxoSveiM7I/myLkf7LziZSPK/rskstNvF3H4ns2Kcd dk=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 20/50] helper-to-tcg: Introduce pseudo instructions Date: Thu, 30 Jul 2026 05:09:54 +0200 Message-ID: <20260730031025.12926-21-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381005710158500 Content-Type: text/plain; charset="utf-8" "pseudo" instructions makes it easy to add custom instructions to LLVM IR in the form of calls to undefined functions. These will be used in future commits to express functionality present in TCG that is missing from LLVM IR (certain vector ops.), or to simplify the backend by collecting similar instruction mappings into a single opcode (idendity mapping). Mapping from a call instructions in LLVM IR to an enum representing the pseudo instruction is also handled, this avoids string comparisons in the backend, and is easy to switch over. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- .../helper-to-tcg/include/PseudoInst.hpp | 75 +++++++ .../helper-to-tcg/include/PseudoInst.inc | 78 ++++++++ subprojects/helper-to-tcg/meson.build | 1 + subprojects/helper-to-tcg/src/PseudoInst.cpp | 183 ++++++++++++++++++ 4 files changed, 337 insertions(+) create mode 100644 subprojects/helper-to-tcg/include/PseudoInst.hpp create mode 100644 subprojects/helper-to-tcg/include/PseudoInst.inc create mode 100644 subprojects/helper-to-tcg/src/PseudoInst.cpp diff --git a/subprojects/helper-to-tcg/include/PseudoInst.hpp b/subprojects= /helper-to-tcg/include/PseudoInst.hpp new file mode 100644 index 0000000000..ef0b03cb5b --- /dev/null +++ b/subprojects/helper-to-tcg/include/PseudoInst.hpp @@ -0,0 +1,75 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include + +#include +#include +#include +#include + +// Pseudo instructions refers to extra LLVM instructions implemented as +// calls to undefined functions. They are useful for amending LLVM IR to +// simplify mapping to TCG in the backend, e.g. +// +// %2 =3D call i32 @IdentityMap.i32.i16(i16 %1) +// +// is a pseudo opcode used to communicate that %1 and %2 should be mapped +// to the same value in TCG. + +enum PseudoInstArg { + ArgAny, + ArgInt, + ArgVec, + ArgPtr, + ArgLabel, + ArgVoid, +}; + +// Define an enum `PseudoInst` consisting of the names of pseudo instructi= ons +// defined in "PseudoInst.inc". +#define PSEUDO_INST_DEF(name, ret, args) name +enum PseudoInst : uint8_t { +#include "PseudoInst.inc" +}; +#undef PSEUDO_INST_DEF + +// Retrieve string representation and argument counts for a given +// pseudo instruction. +const char *pseudoInstName(PseudoInst Inst); +uint8_t pseudoInstArgCount(PseudoInst Inst); +llvm::ArrayRef pseudoInstArgTypes(PseudoInst Inst); + +// Maps `PseudoInst`, return type, and argument types, to a `FunctionCalle= e` +// that can be called. Provided argument types are matched against +// "PseudoInst.inc" for verification and an assert triggers on failure. +llvm::FunctionCallee pseudoInstFunction(llvm::Module &M, PseudoInst Inst, + llvm::Type *RetType, + llvm::ArrayRef ArgTy= pes); + +// Convenience function that gets a pseudo instruction via +// `pseudoInstFunction()` and creates a call to it via the provided `IRBui= lder`. +llvm::CallInst *createPseudoInstCall(llvm::Module &M, + llvm::IRBuilder<> &Builder, + PseudoInst Inst, llvm::Type *RetType, + llvm::ArrayRef Values); + +// Reverse mapping of above, takes a call instruction and attempts to map = the +// callee to a `PseudoInst`. +PseudoInst getPseudoInstFromCall(const llvm::CallInst *Call); diff --git a/subprojects/helper-to-tcg/include/PseudoInst.inc b/subprojects= /helper-to-tcg/include/PseudoInst.inc new file mode 100644 index 0000000000..003d3fb186 --- /dev/null +++ b/subprojects/helper-to-tcg/include/PseudoInst.inc @@ -0,0 +1,78 @@ +PSEUDO_INST_DEF(InvalidPseudoInst, ArgVoid, PSEUDO_INST_ARGVEC()), +// Identity mapping +PSEUDO_INST_DEF(IdentityMap, ArgAny, PSEUDO_INST_ARGVEC(ArgAny)), +// Pointer arithmetic +PSEUDO_INST_DEF(PtrAdd, ArgPtr, PSEUDO_INST_ARGVEC(ArgPtr, Arg= Int)), +// Global accesses +PSEUDO_INST_DEF(AccessGlobalArray, ArgInt, PSEUDO_INST_ARGVEC(ArgInt, Arg= Int, ArgInt)), +PSEUDO_INST_DEF(AccessGlobalValue, ArgInt, PSEUDO_INST_ARGVEC(ArgInt, Arg= Int)), +// Conditional branch +PSEUDO_INST_DEF(Brcond, ArgVoid, PSEUDO_INST_ARGVEC(ArgInt, Ar= gInt, ArgInt, ArgInt, ArgLabel, ArgLabel)), +// Conditional move +PSEUDO_INST_DEF(Movcond, ArgInt, PSEUDO_INST_ARGVEC(ArgInt, Arg= Int, ArgInt, ArgInt, ArgInt)), +// Vector creation ops +PSEUDO_INST_DEF(VecSplat, ArgVec, PSEUDO_INST_ARGVEC(ArgInt)), +PSEUDO_INST_DEF(VecConstant, ArgVec, PSEUDO_INST_ARGVEC(ArgVec)), +// Vector unary ops +PSEUDO_INST_DEF(VecNot, ArgVec, PSEUDO_INST_ARGVEC(ArgVec)), +// Vector scalar binary ops +PSEUDO_INST_DEF(VecAddScalar, ArgVec, PSEUDO_INST_ARGVEC(ArgVec, Arg= Int)), +PSEUDO_INST_DEF(VecSubScalar, ArgVec, PSEUDO_INST_ARGVEC(ArgVec, Arg= Int)), +PSEUDO_INST_DEF(VecMulScalar, ArgVec, PSEUDO_INST_ARGVEC(ArgVec, Arg= Int)), +PSEUDO_INST_DEF(VecXorScalar, ArgVec, PSEUDO_INST_ARGVEC(ArgVec, Arg= Int)), +PSEUDO_INST_DEF(VecOrScalar, ArgVec, PSEUDO_INST_ARGVEC(ArgVec, Arg= Int)), +PSEUDO_INST_DEF(VecAndScalar, ArgVec, PSEUDO_INST_ARGVEC(ArgVec, Arg= Int)), +PSEUDO_INST_DEF(VecShlScalar, ArgVec, PSEUDO_INST_ARGVEC(ArgVec, Arg= Int)), +PSEUDO_INST_DEF(VecLShrScalar, ArgVec, PSEUDO_INST_ARGVEC(ArgVec, Arg= Int)), +PSEUDO_INST_DEF(VecAShrScalar, ArgVec, PSEUDO_INST_ARGVEC(ArgVec, Arg= Int)), +// Vector unary ops that stores to pointer +PSEUDO_INST_DEF(VecNotStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec)), +// Vector binary ops that stores to pointer +PSEUDO_INST_DEF(VecAddStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgVec)), +PSEUDO_INST_DEF(VecSubStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgVec)), +PSEUDO_INST_DEF(VecMulStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgVec)), +PSEUDO_INST_DEF(VecXorStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgVec)), +PSEUDO_INST_DEF(VecOrStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgVec)), +PSEUDO_INST_DEF(VecAndStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgVec)), +PSEUDO_INST_DEF(VecShlStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgVec)), +PSEUDO_INST_DEF(VecLShrStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgVec)), +PSEUDO_INST_DEF(VecAShrStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgVec)), +PSEUDO_INST_DEF(VecAddScalarStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgInt)), +PSEUDO_INST_DEF(VecSubScalarStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgInt)), +PSEUDO_INST_DEF(VecMulScalarStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgInt)), +PSEUDO_INST_DEF(VecXorScalarStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgInt)), +PSEUDO_INST_DEF(VecOrScalarStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgInt)), +PSEUDO_INST_DEF(VecAndScalarStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgInt)), +PSEUDO_INST_DEF(VecShlScalarStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgInt)), +PSEUDO_INST_DEF(VecLShrScalarStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgInt)), +PSEUDO_INST_DEF(VecAShrScalarStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, Ar= gVec, ArgInt)), +// Host memory operations +// vaddr, value si= gn size endian +PSEUDO_INST_DEF(GuestLoad, ArgInt, PSEUDO_INST_ARGVEC(ArgInt, Ar= gInt, ArgInt, ArgInt)), +PSEUDO_INST_DEF(GuestStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgInt, ArgInt, = ArgInt, ArgInt)), +// ... +PSEUDO_INST_DEF(VecTruncStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgInt, = ArgPtr, ArgVec)), +PSEUDO_INST_DEF(VecZExtStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgInt, = ArgPtr, ArgVec)), +PSEUDO_INST_DEF(VecSExtStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgInt, = ArgPtr, ArgVec)), +PSEUDO_INST_DEF(VecSignedSatAddStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgVec, ArgVec)), +PSEUDO_INST_DEF(VecSignedSatSubStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgVec, ArgVec)), +PSEUDO_INST_DEF(VecSelectStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgInt, = ArgPtr, ArgVec, ArgVec, ArgVec)), +PSEUDO_INST_DEF(VecFunnelShrStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgVec, ArgVec, ArgVec)), +PSEUDO_INST_DEF(VecAbsStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgVec)), +PSEUDO_INST_DEF(VecSignedMaxStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgVec, ArgVec)), +PSEUDO_INST_DEF(VecUnsignedMaxStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgVec, ArgVec)), +PSEUDO_INST_DEF(VecSignedMinStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgVec, ArgVec)), +PSEUDO_INST_DEF(VecUnsignedMinStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgVec, ArgVec)), +PSEUDO_INST_DEF(VecCtlzStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgVec)), +PSEUDO_INST_DEF(VecCttzStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgVec)), +PSEUDO_INST_DEF(VecCtpopStore, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgVec)), +PSEUDO_INST_DEF(VecWideCondBitsel, ArgVec, PSEUDO_INST_ARGVEC(ArgVec, A= rgVec, ArgVec)), +PSEUDO_INST_DEF(VecWideCondBitselStore, ArgVoid, PSEUDO_INST_ARGVEC(Arg= Ptr, ArgVec, ArgVec, ArgVec)), +PSEUDO_INST_DEF(VecCompare, ArgVec, PSEUDO_INST_ARGVEC(ArgInt, A= rgVec, ArgVec)), +PSEUDO_INST_DEF(VecSelect, ArgVec, PSEUDO_INST_ARGVEC(ArgInt, A= rgVec, ArgVec)), + +PSEUDO_INST_DEF(SignExtract, ArgInt, PSEUDO_INST_ARGVEC(ArgInt, A= rgInt, ArgInt)), +PSEUDO_INST_DEF(Extract, ArgInt, PSEUDO_INST_ARGVEC(ArgInt, A= rgInt, ArgInt)), + +PSEUDO_INST_DEF(Exception, ArgVoid, PSEUDO_INST_ARGVEC(ArgPtr, = ArgInt)), +PSEUDO_INST_DEF(GetPC, ArgInt, PSEUDO_INST_ARGVEC()), diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 4fd0ddb778..b3a3de6297 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -43,6 +43,7 @@ sources =3D [ 'src/LlvmCompat.cpp', 'src/Pipeline.cpp', 'src/PrepareForOptPass/PrepareForOptPass.cpp', + 'src/PseudoInst.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/PseudoInst.cpp b/subprojects/hel= per-to-tcg/src/PseudoInst.cpp new file mode 100644 index 0000000000..91e0f25e3d --- /dev/null +++ b/subprojects/helper-to-tcg/src/PseudoInst.cpp @@ -0,0 +1,183 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "PseudoInst.hpp" +#include "LlvmCompat.hpp" + +#include +#include +#include +#include +#include + +using namespace llvm; + +// Define an array `PseudoInstName[]`, indexed by `PseudoInst` and mapping +// to a string representation of the enum. +#define PSEUDO_INST_DEF(name, ret, args) #name +static const char *PseudoInstName[] =3D { +#include "PseudoInst.inc" +}; +#undef PSEUDO_INST_DEF + +// Define an array `PseudoInstArgTypes[]` indexed by `PseudoInst` and +// mapping to an array of `PseudoInstArg` representing allowed argument ty= pes. +#define PSEUDO_INST_ARGVEC(...) {__VA_ARGS__} + +#define PSEUDO_INST_DEF(name, ret, args) args +static const SmallVector PseudoInstArgTypes[] =3D { +#include "PseudoInst.inc" +}; +#undef PSEUDO_INST_DEF +#undef PSEUDO_INST_ARGVEC + +// In order to map from a `Function *` to a `PseudoInst`, we keep a map +// of all functions created, this simplifies mapping of callees to +// a `PseudoInst` that can be switched over. +static DenseMap MapFuncToInst; + +// Converts llvm `Type`s to a string representation +// that can be embedded in function names for basic overloading. +// +// Ex. +// +// [8 x i8] -> "a8xi8" +// <128 x i8> -> "v128xi8" +// +// LLVM has an implementation of a similar function used by intrinsics, +// called `getMangledTypeStr`, but it's not exposed. +inline std::string getMangledTypeStr(Type *Ty) { + std::string TypeStr =3D ""; + llvm::raw_string_ostream TypeStream(TypeStr); + switch (Ty->getTypeID()) { + case Type::ArrayTyID: { + auto *ArrayTy =3D cast(Ty); + std::string ElementStr =3D getMangledTypeStr(ArrayTy->getElementTy= pe()); + TypeStream << "a" << ArrayTy->getNumElements() << "x" << ElementSt= r; + } break; + case Type::FixedVectorTyID: { + auto *VecTy =3D cast(Ty); + uint32_t ElementCount =3D compat::getVectorElementCount(VecTy); + std::string ElementStr =3D getMangledTypeStr(VecTy->getElementType= ()); + TypeStream << "v" << ElementCount << "x" << ElementStr; + } break; + case Type::StructTyID: { + auto *StructTy =3D cast(Ty); + TypeStream << StructTy->getName(); + } break; + case Type::IntegerTyID: { + auto *IntTy =3D cast(Ty); + TypeStream << "i" << IntTy->getBitWidth(); + } break; + case Type::PointerTyID: { + TypeStream << "p"; + } break; + default: + abort(); + } + return TypeStream.str(); +} + +// Access functions into the static defined above. + +const char *pseudoInstName(PseudoInst Inst) { return PseudoInstName[Inst];= } + +uint8_t pseudoInstArgCount(PseudoInst Inst) { + return PseudoInstArgTypes[Inst].size(); +} + +llvm::ArrayRef pseudoInstArgTypes(PseudoInst Inst) { + return PseudoInstArgTypes[Inst]; +} + +// Match LLVM type against `PseudoIntsArg`. +static void assertMatchingType(PseudoInstArg Expected, Type *Ty) { + const Type::TypeID Id =3D Ty->getTypeID(); + switch (Expected) { + case ArgAny: + return; + case ArgInt: + assert(Id =3D=3D Type::IntegerTyID); + return; + case ArgVec: + assert(Id =3D=3D Type::FixedVectorTyID); + return; + case ArgPtr: + assert(Id =3D=3D Type::PointerTyID); + return; + case ArgLabel: + assert(Id =3D=3D Type::LabelTyID); + return; + case ArgVoid: + assert(Id =3D=3D Type::VoidTyID); + return; + default: + abort(); + }; +} + +llvm::FunctionCallee pseudoInstFunction(llvm::Module &M, PseudoInst Inst, + llvm::Type *RetType, + llvm::ArrayRef ArgTy= pes) { + ArrayRef PArgTypes =3D pseudoInstArgTypes(Inst); + assert(PArgTypes.size() =3D=3D ArgTypes.size()); + for (size_t I =3D 0; I < ArgTypes.size(); ++I) { + assertMatchingType(PArgTypes[I], ArgTypes[I]); + } + + auto *FT =3D llvm::FunctionType::get(RetType, ArgTypes, false); + + std::string FnName{PseudoInstName[Inst]}; + if (!RetType->isVoidTy()) { + FnName +=3D "."; + FnName +=3D getMangledTypeStr(RetType); + } + for (llvm::Type *Ty : ArgTypes) { + if (Ty->isLabelTy()) { + continue; + } + FnName +=3D "."; + FnName +=3D getMangledTypeStr(Ty); + } + + llvm::FunctionCallee Fn =3D M.getOrInsertFunction(FnName, FT); + auto *F =3D cast(Fn.getCallee()); + MapFuncToInst.insert({F, Inst}); + + return Fn; +} + +llvm::CallInst *createPseudoInstCall(llvm::Module &M, IRBuilder<> &Builder, + PseudoInst Inst, llvm::Type *RetType, + llvm::ArrayRef Values)= { + SmallVector ArgTypes; + for (Value *V : Values) { + ArgTypes.push_back(V->getType()); + } + + FunctionCallee Fn =3D pseudoInstFunction(M, Inst, RetType, ArgTypes); + return Builder.CreateCall(Fn, Values); +} + +PseudoInst getPseudoInstFromCall(const CallInst *Call) { + Function *F =3D Call->getCalledFunction(); + auto It =3D MapFuncToInst.find(F); + if (It =3D=3D MapFuncToInst.end()) { + return InvalidPseudoInst; + } + return It->second; +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381050; cv=none; d=zohomail.com; s=zohoarc; b=eQnZGcBleHSpf3rndA7L5S1lmQL6DVSHpxm7LMzLMsrW/nI8tUW5aXiIAIL6wQz6Ymj9tAfRmCyBltMHDMSp8+0SnPM1RyCLlGph517I8nJrLbQANa6XGeMd7R4XZ85qITBg193BHCzcG3BRh4rEIYT2gymrPeGDV01MfgvPNKI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381050; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=LRMzawlJ3Kw59JwVhx4oKCorGEMhoXcYEID8YEaEEqs=; b=D25fHGqoxMifv3g/72L9UGqxC0wXBY3K4Q4MSYW07dfMohSTPSKtsbie3oqUAgAEdG2OcCxAXnfoUJrqPlnPGCIvbgXEkqliACAS+fBAwPZ6tvx7WKTygv6tnh+0LnnmR1T+LMp3/K4ia+pqnuQ0+bG2SKeXeFzdtAR3uovQKng= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178538104989554.2889126221711; Wed, 29 Jul 2026 20:10:49 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6Y-0002es-LM; Wed, 29 Jul 2026 23:06:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6X-0002SO-0g for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:41 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6U-0002vo-Tb for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:40 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=LRMzawlJ3Kw59JwVhx4oKCorGEMhoXcYEID8YEaEEqs=; b=IiiIKoamNBqq1Jy KIwh6ayfWOPaEQWZ/QEgQB8DCQKuB/leIQRazrT0jg7KZky8kvWKWOxWtcdOFcE6unUARYJ8hUnE8 7rJGn23tvLOQbkRYGW+jcc6BhyPq0zBhiFUb5+3mCSiCDa/3WUh7mnaEsqUonbAxMVt59Q+VJ4Amp MI=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 21/50] helper-to-tcg: Add guest vector layout description Date: Thu, 30 Jul 2026 05:09:55 +0200 Message-ID: <20260730031025.12926-22-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381051795158500 Content-Type: text/plain; charset="utf-8" Vectors are represented as arrays of host-endian blocks at least 64 bits in size, the size of which is configurable. Lane 0 in each block may be placed either at the most- or least-significant bytes. This covers a wide range of QEMU targets' vector representations. Vector layout information is used later when mapping constant expressions such as constant vectors, and when emitting helper functions for performing size-changing operations. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- .../helper-to-tcg/include/VectorLayout.hpp | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 subprojects/helper-to-tcg/include/VectorLayout.hpp diff --git a/subprojects/helper-to-tcg/include/VectorLayout.hpp b/subprojec= ts/helper-to-tcg/include/VectorLayout.hpp new file mode 100644 index 0000000000..e85f5029d5 --- /dev/null +++ b/subprojects/helper-to-tcg/include/VectorLayout.hpp @@ -0,0 +1,116 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include +#include +#include + +// Vector Layout +// +// Vector layouts among QEMU guests is quite diverse, this header aims to = be +// simple but still capture a large subset of targets. +// +// Guest vectors are assumed to be divided into host-endian blocks of a +// configurable size (>=3D 64-bit and power-of-two), with block 0 always b= eing at +// the lowest address. Blocks in turn are divided into 64-bit columns whi= ch are +// used when interfacing with QEMUs `gvec` API. +// +// Below is a 32-byte <32 x i8> guest vector consisting of 16-byte blocks, +// 8-byte columns, and 1-byte lanes for each element in the vector. Eleme= nts +// count from 1-32 in hex to indicate their position in memory. Note this +// example is for a little-endian host with `LeastSignificant` lane prefer= ence +// meaning lane 0 is at the least significant bytes of each block. +// +// Guest vector <32 x i8> {1, 2, 3, ..., 32} +// +---------------------------------+---------------------------------+ +// | BLOCK 0 | BLOCK 1 | +// +----------------+----------------+----------------+----------------+ +// | COLUMN 0 | COLUMN 1 | COLUMN 2 | COLUMN 3 | +// |0102030405060708|090A0B0C0D0E0F10|1112131415161718|191A1B1C1D1E1F20| +// +// LOW ADDRESS HIGH ADDRESS +// +// On a big-endian host, the vector would instead be expressed in memory as +// +// Guest vector <32 x i8> {1, 2, 3, ..., 32} +// +---------------------------------+---------------------------------+ +// | BLOCK 0 | BLOCK 1 | +// +----------------+----------------+----------------+----------------+ +// | COLUMN 1 | COLUMN 0 | COLUMN 3 | COLUMN 2 | +// |100F0E0D0C0B0A09|0807060504030201|201F1E1D1C1B1A19|1817161514131211| +// +// LOW ADDRESS HIGH ADDRESS +// +// with the column order having shifted to make sure the host-endian blocks +// retain the same value. Blocks are also allowed to be equal or greater = in +// size that the guest vector, at which point the entire memory view of the +// vector would reverse when going from a little to big-endian host. +// +// The lane preference may also be changed to `MostSignificant` which for = the +// little-endian example places lane 0 and the highest address of block 0. +// Note, that `MostSignificant` on little-endian and `LeastSignificant` on +// big-endian hosts are equivalent in their memory representation, but will +// differ in how they are emitted in C: +// +// // MostSignificant, little endian +// uint64_t vec[] =3D {0x90A0B0C0D0E0F10, 0x102030405060708, ...}; +// +// // LeastSignificant, big endian +// uint64_t vec[] =3D {0x100F0E0D0C0B0A09, 0x807060504030201, ...}; +// + +enum LanePreference { + LeastSignificant, + MostSignificant, +}; + +struct VectorLayout { + bool HostBigEndian; + LanePreference Lane0; + size_t BlockBytes; + + inline size_t index(bool Reverse, size_t Count, size_t I, size_t J) co= nst { + if (Reverse) { + return Count * I + (J ^ (Count - 1)); + } else { + return Count * I + J; + } + } + + // Return the index into a linear array of lane L in column C + inline size_t indexLane(size_t LanesPerColumn, size_t C, size_t L) con= st { + const bool Reverse =3D (Lane0 =3D=3D MostSignificant); + return index(Reverse, LanesPerColumn, C, L); + } + + // Return the index into a linear array of + inline size_t indexBlock(size_t BlocksPerVec, size_t I) const { + const bool Reverse =3D (HostBigEndian ^ (Lane0 =3D=3D MostSignific= ant)); + return index(Reverse, BlocksPerVec, 0, I); + } + + //inline uint64_t column(llvm::ArrayRef Lanes) { + // uint64_t Column =3D 0; + // const size_t LanesPerColumn =3D 64 / ElementSize; + // for (size_t L =3D 0; L < LanesPerColumn; ++L) { + // const size_t Index =3D VL.indexLane(LanesPerColumn, C, L); + // Column |=3D Ints[Index] << (ElementSize * L); + // } + //} +}; --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380859; cv=none; d=zohomail.com; s=zohoarc; b=VnsvtxTmorcedfiyeUxQ7HE0dWSRK61VovDB/Lr6gpz32ZVMQkvFkljFP2ohJka2fhlL5+FXLA9JYoxm3AwrFyEZ6XzyfmGpeKg0cfemhtWBKxoJU705e6IlhW/Wc12YvmG0yG/wfgL6iTMWmJLarj+v9JWF1cZg45MSNx93pvM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380859; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=IkQugLx6QLVgUoZlVKl4ZiXCLCO5b235a651y44fLYM=; b=dX/69HChWxIsAhweWd8GkAmKnMTpBdpoBcSfUQtDr+2FztONLBdL8v3o3h7xR9boZNTFZ/nuoTr/aLN+iwiE4nuTydY/4u8oxuXqEHM/xRBSWD0PWkSDJYv3BgajavOjn66zXhGalIb+M2lP3b9hMv3gyITVFkAoBMT7KeAw2gI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380859093857.9103383031154; Wed, 29 Jul 2026 20:07:39 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6c-0002xn-GL; Wed, 29 Jul 2026 23:06:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6Z-0002nV-OW for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:43 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6X-0002vt-98 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=IkQugLx6QLVgUoZlVKl4ZiXCLCO5b235a651y44fLYM=; b=uePriEQZLUAPXN6 HH/VsIUgtnAF0dq9+1uCuAXXyykbtPaCTqNQ5Zl9m3/RU3rV5iTB9A9ml3SCjApva8Mkhylj8SzcP ObqrFgd+GxWgBo6x/ad8aKJ1r/VcmqhEOZjNh2jq7ZnUjxnWp1SHPa2TYY7+s/udjdMfGJJIUtvuR 9Y=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 22/50] helper-to-tcg: Introduce PrepareForTcgPass Date: Thu, 30 Jul 2026 05:09:56 +0200 Message-ID: <20260730031025.12926-23-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380861195158501 Content-Type: text/plain; charset="utf-8" Adds a new pass over the LLVM module which runs post-optimization with the end-goal of: * Culling functions which aren't worth translating; * Canonicalizing the IR to something closer to TCG, and; * Extracting information which may be useful in the backend pass. The bulk of IR transformations occur in the canonicalization phase, with a handful occuring later in the packend. This commits sets up a new LLVM pass over the IR module and runs it from the pipeline. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- .../helper-to-tcg/include/CmdLineOptions.hpp | 2 ++ .../include/PrepareForTcgPass.hpp | 27 +++++++++++++++++++ subprojects/helper-to-tcg/meson.build | 1 + subprojects/helper-to-tcg/src/Pipeline.cpp | 24 +++++++++++++++++ .../PrepareForTcgPass/PrepareForTcgPass.cpp | 25 +++++++++++++++++ 5 files changed, 79 insertions(+) create mode 100644 subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp create mode 100644 subprojects/helper-to-tcg/src/PrepareForTcgPass/Prepare= ForTcgPass.cpp diff --git a/subprojects/helper-to-tcg/include/CmdLineOptions.hpp b/subproj= ects/helper-to-tcg/include/CmdLineOptions.hpp index ca1cb59835..bfdd3ebe41 100644 --- a/subprojects/helper-to-tcg/include/CmdLineOptions.hpp +++ b/subprojects/helper-to-tcg/include/CmdLineOptions.hpp @@ -23,3 +23,5 @@ extern llvm::cl::list InputFiles; // Options for PrepareForOptPass extern llvm::cl::opt TranslateAllHelpers; +// Options for PrepareForTcgPass +extern llvm::cl::opt TcgGlobalMappingsName; diff --git a/subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp b/subp= rojects/helper-to-tcg/include/PrepareForTcgPass.hpp new file mode 100644 index 0000000000..90bc9402cb --- /dev/null +++ b/subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp @@ -0,0 +1,27 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include + +class PrepareForTcgPass : public llvm::PassInfoMixin { +public: + PrepareForTcgPass() {} + llvm::PreservedAnalyses run(llvm::Module &M, + llvm::ModuleAnalysisManager &MAM); +}; diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index b3a3de6297..c2926652f3 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -44,6 +44,7 @@ sources =3D [ 'src/Pipeline.cpp', 'src/PrepareForOptPass/PrepareForOptPass.cpp', 'src/PseudoInst.cpp', + 'src/PrepareForTcgPass/PrepareForTcgPass.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp index 571276de24..6058718a9c 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -18,6 +18,7 @@ #include "CmdLineOptions.hpp" #include "LlvmCompat.hpp" #include "PrepareForOptPass.hpp" +#include "PrepareForTcgPass.hpp" =20 #if LLVM_VERSION_MAJOR =3D=3D 15 #include @@ -32,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +45,7 @@ #include #include #include +#include #include =20 #define DEBUG_TYPE "pipeline" @@ -70,6 +73,13 @@ cl::opt TranslateAllHelpers( "translate-all-helpers", cl::init(false), cl::desc("Translate all functions starting with helper_*"), cl::cat(Ca= t)); =20 +// Options for PrepareForTcgPass +cl::opt TcgGlobalMappingsName( + "tcg-global-mappings", + cl::desc(""), + cl::Required, cl::cat(Cat)); + // Define a TargetTransformInfo (TTI) subclass, this allows for overriding // common per-llvm-target information expected by other LLVM passes, such // as the width of the largest scalar/vector registers. Needed for consis= tent @@ -214,5 +224,19 @@ int main(int argc, char **argv) { MPM.addPass( PB.buildModuleOptimizationPipeline(compat::OptimizationLevel::Oz, = {})); =20 + // + // Next, we run our final transformations, including removing phis and= our + // own instruction combining that prioritizes instructions that map mo= re + // easily to TCG. + // + + MPM.addPass(PrepareForTcgPass()); + MPM.addPass(VerifierPass()); + { + FunctionPassManager FPM; + FPM.addPass(DCEPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } + return 0; } diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass= .cpp new file mode 100644 index 0000000000..cea6573e41 --- /dev/null +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp @@ -0,0 +1,25 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "PrepareForTcgPass.hpp" + +using namespace llvm; + +PreservedAnalyses PrepareForTcgPass::run(Module &M, ModuleAnalysisManager = &MAM) +{ + return PreservedAnalyses::none(); +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381119; cv=none; d=zohomail.com; s=zohoarc; b=OJIwMI2knLIgl4RY0Gx95m5gZJN6X3pDsipPF/Cux1rl+AYU0hNpgpaO/fHUOmHA/KGemx4EF4eSMK7CivNvzXvzQO9a1ARdI/OpHF2jvdSFxQWm+nGzKxBvN5rOPcM8VBQBngSW/W2CyggLNajqmF1R406KcKQnNcbpjIKjOpM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381119; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=LRmxL4SoF9BQ3qcMgroP5TJKzuambQWaFM+uYcKhGIU=; b=cm+66BIuDPtU0gpqcFLqo6NAjkAdZtCGU1P/KU8MLMlTHBtxCvie2TJnOKNpZNNJ68OTyQuZLh9l+VgR4tnsVMD+EZ2Oqms1HRiSpFR8ZqH2nJwHWUeZft87h2QyC8gapGzM1YgjShWM7K1UeCSF2HOdrO5G+CjByzeBp0E5VsY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381119289699.0500566134991; Wed, 29 Jul 2026 20:11:59 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6e-000374-78; Wed, 29 Jul 2026 23:06:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6b-0002vo-2U for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:45 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6Z-0002w8-A2 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=LRmxL4SoF9BQ3qcMgroP5TJKzuambQWaFM+uYcKhGIU=; b=olLaeJD7v7SN/K5 x1wY02RiFKuVhEhZQDwq66rEybN8THhyiUuVsJqWPu+a3QOmS0ezw61Gj+YK+QHtIKMJu0/2gOTJQ 0e6g9W6H+IJpo9PNXeg2ZceEb1jq5yhMbXbXJ4346/Em9ow8NQkqH3kIwYMYw6oXBB7a7DTnNj5HE b8=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 23/50] helper-to-tcg: PrepareForTcgPass, remove functions with cycles Date: Thu, 30 Jul 2026 05:09:57 +0200 Message-ID: <20260730031025.12926-24-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381120014158500 Content-Type: text/plain; charset="utf-8" Functions with cycles are removed for two primary reasons: * As a simplifying assumption for register allocation which occurs down the line, and; * If a function contains cycles post-optimization neither unrolling or loop vectorization were deemed beneficial, and the function _might_ be better suited as a helper anyway. Cycles are detected by iterating over Strongly Connected Components (SCCs) which imply the existence of cycles if a SCC contains more than one node, or it has a self-edge. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- .../PrepareForTcgPass/PrepareForTcgPass.cpp | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass= .cpp index cea6573e41..41f317ed0b 100644 --- a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp @@ -17,9 +17,39 @@ =20 #include "PrepareForTcgPass.hpp" =20 +#include +#include +#include +#include + using namespace llvm; =20 -PreservedAnalyses PrepareForTcgPass::run(Module &M, ModuleAnalysisManager = &MAM) -{ +static void removeFunctionsWithLoops(Module &M, ModuleAnalysisManager &MAM= ) { + // Iterate over all Strongly Connected Components (SCCs), a SCC implies + // the existence of loops if: + // - it has more than one node, or; + // - it has a self-edge. + SmallPtrSet FunctionsToRemove; + for (Function &F : M) { + if (F.isDeclaration()) { + continue; + } + for (auto It =3D scc_begin(&F); !It.isAtEnd(); ++It) { + if (It.hasCycle()) { + FunctionsToRemove.insert(&F); + break; + } + } + } + + for (Function *F : FunctionsToRemove) { + F->setComdat(nullptr); + F->deleteBody(); + } +} + +PreservedAnalyses PrepareForTcgPass::run(Module &M, + ModuleAnalysisManager &MAM) { + removeFunctionsWithLoops(M, MAM); return PreservedAnalyses::none(); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381008; cv=none; d=zohomail.com; s=zohoarc; b=kAzvkDqwLd06LOjYGP1IJ8IiS4XO1fJsoubpkfnD6vZgxDARUbNCRaJfla0w7abqPLREkkZrJ6AvIi4WYaYO3r4Uy2W+i4GlJRiJMq2BgzFK6NZH1oC/esaf/XlMl3dF/9WAZJv+zVLtf+tO1tni3jRtX+YOky8VisQhBeOSjSk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381008; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=B+tS5VBIr0cK4rOug74NF63kx8YZ4luM84qgVcRBTkM=; b=NhNi1+EH0NbHrNABKeoFDUYM5TIuL6L0WYCXXDPny7s7H2+vNIHNL68rsS73n6N8WTTdOHSHHcGT/kKxyiHN14Uq7PS3FLJYrNo64+kGrIN/lfkfB6CdScnKiKDdv/kXPh6dSMK0DpLJFR+kVev87mD7KoSW71WPDHMxG2agQQw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178538100824922.357811975763752; Wed, 29 Jul 2026 20:10:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6k-0003gH-Hh; Wed, 29 Jul 2026 23:06:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6g-0003OF-KA for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:52 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6d-0002wV-9b for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:49 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=B+tS5VBIr0cK4rOug74NF63kx8YZ4luM84qgVcRBTkM=; b=TzpwxNls2pCws2b 2EsanPOCvSLc2gJYh6NPZB5vyecCJYgXoR/a1VK4VsTXKDtj9rXUK9q9K10y0u9sP3Vt7i4M0SEvJ ux9v9OVIFUmHWXchXF4pna+D1RFz1nVT0N+ST8JsaQu7xqOACSUGIPC5P8hMu8dDAlkJuXpdk9PgQ 54=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 24/50] helper-to-tcg: PrepareForTcgPass, demote PHI nodes Date: Thu, 30 Jul 2026 05:09:58 +0200 Message-ID: <20260730031025.12926-25-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381009580158500 Content-Type: text/plain; charset="utf-8" PHI nodes have no clear analogue in TCG, this commits converts them to stack accesses using a built-in LLVM transformation. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- .../PrepareForTcgPass/PrepareForTcgPass.cpp | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass= .cpp index 41f317ed0b..d8530406ad 100644 --- a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp @@ -20,7 +20,10 @@ #include #include #include +#include +#include #include +#include =20 using namespace llvm; =20 @@ -48,8 +51,28 @@ static void removeFunctionsWithLoops(Module &M, ModuleAn= alysisManager &MAM) { } } =20 +inline void demotePhis(Function &F) { + if (F.isDeclaration()) { + return; + } + + SmallVector Phis; + for (auto &I : instructions(F)) { + if (auto *Phi =3D dyn_cast(&I)) { + Phis.push_back(Phi); + } + } + + for (auto *Phi : Phis) { + DemotePHIToStack(Phi); + } +} + PreservedAnalyses PrepareForTcgPass::run(Module &M, ModuleAnalysisManager &MAM) { removeFunctionsWithLoops(M, MAM); + for (Function &F : M) { + demotePhis(F); + } return PreservedAnalyses::none(); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380844; cv=none; d=zohomail.com; s=zohoarc; b=eIut6uJB4qjdpdPCBONkj4pBEK4IUJjtFi7l/+iXheSLa0MOgBgfr/xYaxHDJBROwo/D9lLbLIHTD6VOy1ZySum/iaaHLCtRog/hZDhT5XrPCPANLdRSiiQ7WTvtySA7cvv1TaNqwLhRutGjwiyclvFmD8ixUvp+h9EhfPJVNJw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380844; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=Wm8+yoau+DLBWo1+flB1+I3tcw4dSaa40HqLRuhRzfg=; b=FJG0lYuK4f12FzXNPudOrSDwkAyztelnt99DYgMISemP2yQuIgb0syo/LUNRVGWjwntUvLrFkPuAU5CfpNrz7AylN6U9hAgisblQNtQnTeHb/ry5jLhAXGqpujmj1+24uXxMbcstEPWZJ/6dV1A9gYRXqNRvfA4De4g9L66fK00= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178538084441845.983974167143174; Wed, 29 Jul 2026 20:07:24 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6o-0003oI-Sc; Wed, 29 Jul 2026 23:06:58 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6i-0003Pl-DQ for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:52 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6f-0002wj-Af for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:52 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=Wm8+yoau+DLBWo1+flB1+I3tcw4dSaa40HqLRuhRzfg=; b=CK3PAdywvx1i036 Ql3i5R5QnbXpn8oKSK+05aGGxUeLsm0v4qKIvjsJ5sgBdR/JgDDZ2oQhbTqF9OpTGvqlSNkB4jBPv k47v+2kn9RFUePX8meJKXW9NIm/mMflCHHbRGqLccTttqHmJ/E6WIbSMIkyGeoVAC9G4Hjfw/kmCo m4=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 25/50] helper-to-tcg: PrepareForTcgPass, map TCG globals Date: Thu, 30 Jul 2026 05:09:59 +0200 Message-ID: <20260730031025.12926-26-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380845118158500 Content-Type: text/plain; charset="utf-8" The input LLVM module may define an array of cpu_mapping structs, describing the mapping between fields in a specified struct (usually CPUArchState) and TCG globals. Create a map between offsets into the specified struct and TCG globals (name, size, number of elements, stride) by iterating over the global cpu_mapping array. The name of this array is configurable via the --tcg-global-mappings flag. Signed-off-by: Anton Johansson --- .../include/PrepareForTcgPass.hpp | 6 +- .../helper-to-tcg/include/TcgGlobalMap.hpp | 40 ++++++++++++ subprojects/helper-to-tcg/src/Pipeline.cpp | 9 +-- .../PrepareForTcgPass/PrepareForTcgPass.cpp | 62 +++++++++++++++++++ 4 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 subprojects/helper-to-tcg/include/TcgGlobalMap.hpp diff --git a/subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp b/subp= rojects/helper-to-tcg/include/PrepareForTcgPass.hpp index 90bc9402cb..3e0679b46c 100644 --- a/subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp +++ b/subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp @@ -17,11 +17,15 @@ =20 #pragma once =20 +#include "TcgGlobalMap.hpp" #include =20 class PrepareForTcgPass : public llvm::PassInfoMixin { + TcgGlobalMap &ResultTcgGlobalMap; + public: - PrepareForTcgPass() {} + PrepareForTcgPass(TcgGlobalMap &ResultTcgGlobalMap) + : ResultTcgGlobalMap(ResultTcgGlobalMap) {} llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM); }; diff --git a/subprojects/helper-to-tcg/include/TcgGlobalMap.hpp b/subprojec= ts/helper-to-tcg/include/TcgGlobalMap.hpp new file mode 100644 index 0000000000..ad7ac54608 --- /dev/null +++ b/subprojects/helper-to-tcg/include/TcgGlobalMap.hpp @@ -0,0 +1,40 @@ +#pragma once + +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include +#include +#include +#include + +// `TcgGlobal` describes a field in a struct which has a mapping to a TCG +// global. `Size`, `NumElements`, and `Stride` describe the mapped type, = all +// types are assumed to be integer or arrays of integers. `Code` is the +// expression to be emitted when accessing the mapped global, usually the +// variable name. +struct TcgGlobal { + llvm::StringRef Code; + uint64_t Size; + uint64_t NumElements; + uint64_t Stride; +}; + +// Array of maps between offsets into a mapped struct to the resulting glo= bal +// type, outer array is indexed by the base struct type to handle multiple +// struct-to-global mappings. +using TcgGlobalMap =3D llvm::SmallVector, 1>; diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp index 6058718a9c..f24bb67f0c 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -76,9 +76,9 @@ cl::opt TranslateAllHelpers( // Options for PrepareForTcgPass cl::opt TcgGlobalMappingsName( "tcg-global-mappings", - cl::desc(""), - cl::Required, cl::cat(Cat)); + cl::desc("Name of global cpu_mappings[] used for mapping accesses" + "into a struct to TCG globals"), + cl::init("mappings"), cl::cat(Cat)); =20 // Define a TargetTransformInfo (TTI) subclass, this allows for overriding // common per-llvm-target information expected by other LLVM passes, such @@ -230,7 +230,8 @@ int main(int argc, char **argv) { // easily to TCG. // =20 - MPM.addPass(PrepareForTcgPass()); + TcgGlobalMap TcgGlobals; + MPM.addPass(PrepareForTcgPass(TcgGlobals)); MPM.addPass(VerifierPass()); { FunctionPassManager FPM; diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass= .cpp index d8530406ad..69add43529 100644 --- a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp @@ -16,9 +16,12 @@ // =20 #include "PrepareForTcgPass.hpp" +#include "CmdLineOptions.hpp" =20 #include #include +#include +#include #include #include #include @@ -68,11 +71,70 @@ inline void demotePhis(Function &F) { } } =20 +static StringMap collectTcgGlobals(Module &M, TcgGlobalMap &Result= TcgGlobalMap) { + auto *Map =3D M.getGlobalVariable(TcgGlobalMappingsName); + if (!Map) { + return {}; + } + + // In case the `tcg_global_mappings` array is empty, + // casting to `ConstantArray` will fail, even though it's a + // `[0 x %struct.cpu_tcg_mapping]`. + auto *MapElems =3D dyn_cast(Map->getOperand(0)); + if (!MapElems) { + return {}; + } + + StringMap TypeIndexMap; + + for (auto Row : MapElems->operand_values()) { + auto *ConstRow =3D cast(Row); + + // Get code string + auto *CodePtr =3D ConstRow->getOperand(0); + StringRef CodeStr =3D + cast(CodePtr->getOperand(0))->getAsString(); + CodeStr =3D CodeStr.rtrim('\0'); + + // Get base type name + auto *TypeNamePtr =3D ConstRow->getOperand(2); + StringRef TypeNameStr =3D + cast(TypeNamePtr->getOperand(0))->getAsStri= ng(); + TypeNameStr =3D TypeNameStr.rtrim('\0'); + + // Get offset in cpu env + auto *Offset =3D cast(ConstRow->getOperand(4)); + // Get size of variable in cpu env + auto *SizeInBytes =3D cast(ConstRow->getOperand(5)); + unsigned SizeInBits =3D 8 * SizeInBytes->getLimitedValue(); + + auto *Stride =3D cast(ConstRow->getOperand(6)); + auto *NumElements =3D cast(ConstRow->getOperand(7)); + + if (auto It =3D TypeIndexMap.find(TypeNameStr); + It =3D=3D TypeIndexMap.end()) { + TypeIndexMap[TypeNameStr] =3D ResultTcgGlobalMap.size(); + ResultTcgGlobalMap.emplace_back(); + } + + const size_t Index =3D TypeIndexMap[TypeNameStr]; + ResultTcgGlobalMap[Index][Offset->getLimitedValue()] =3D { + CodeStr, + SizeInBits, + NumElements->getLimitedValue(), + Stride->getLimitedValue(), + }; + } + + return TypeIndexMap; +} + PreservedAnalyses PrepareForTcgPass::run(Module &M, ModuleAnalysisManager &MAM) { removeFunctionsWithLoops(M, MAM); for (Function &F : M) { demotePhis(F); } + const StringMap TypeIndexMap =3D collectTcgGlobals(M, ResultTc= gGlobalMap); return PreservedAnalyses::none(); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381091; cv=none; d=zohomail.com; s=zohoarc; b=Xn6lsn6ZdEofUarDJkRMHMPLbvLo5LBdeePUE1kDQmwsCRsRtB3+oZCK5W4iSl95GJeA7Ijx1zz9p4DJTs77ELM8GyrraJ/ZyhEkVhfZvr5LcpYrkilfTwArizZ7FgWXTYhUMzPTvW8oUxEBW3DbA/EGAIOPoPpexFKdQenRblc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381091; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=KEcf/6fUzAX7NA/vh4m4OtuUSMiXhSnGfIf10mAjLT4=; b=iXcQUTTgDl+m+tIBKTbdloje0FM48j31oIprUhrH9bIahERbe1aGLLl0BJKSFMK3g5DDLJ7RmbmkPE6aOtboXXBT/P+rWg2wt78K/cBbbDdp+wijUjdX5+xkVUH+7SJQfJcQLUgzZ/6XMI/xH9tyN8X7euN+XZNttCYuhzEn12k= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381091055901.2735093048517; Wed, 29 Jul 2026 20:11:31 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH6r-0003xB-83; Wed, 29 Jul 2026 23:07:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6n-0003ow-Pw for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:58 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6i-0002wv-N9 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:06:56 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=KEcf/6fUzAX7NA/vh4m4OtuUSMiXhSnGfIf10mAjLT4=; b=qaDsGmiWzf73uLh v6WHX3jbp7t6ez1TAW1XLUZgPsrqR60BV3EM+azj29SCqf95hOBx491dD3azUx6xZq+crCJfwKBzW ejvo/whh0u/jpQxSPRZlVqESZHWaC08FNSYfdqRerOw649zR54PxLpIONr5fPjkjFlEjMuZHOfq8c LI=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 26/50] helper-to-tcg: PrepareForTcgPass, transform GEPs Date: Thu, 30 Jul 2026 05:10:00 +0200 Message-ID: <20260730031025.12926-27-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381092114158500 Content-Type: text/plain; charset="utf-8" getelementpointer (GEP) instructions in LLVM IR represent general pointer arithmetic (struct field access, array indexing, ...). From the perspective of TCG, three distinct cases are important and are transformed into pseudo instructions respectively: * Struct accesses whose offset into the struct map to a TCG global are transformed into `call @AccessGlobalValue(structindex, offset)`; * Struct accesses whose offset into the struct map to an array of TCG globals are transformed into `call @AccessGlobalArray(structindex, offs= et, index)`; * Otherwise, access is converted to general pointer arithmetic in LLVM IR= using `call @PtrAdd(...)`. These three cases are treated differently in the backend and all other GEPs are considered erroneous. Signed-off-by: Anton Johansson --- .../include/PrepareForTcgPass.hpp | 7 +- subprojects/helper-to-tcg/meson.build | 1 + subprojects/helper-to-tcg/src/Pipeline.cpp | 2 +- .../PrepareForTcgPass/PrepareForTcgPass.cpp | 4 + .../src/PrepareForTcgPass/TransformGEPs.cpp | 355 ++++++++++++++++++ .../src/PrepareForTcgPass/TransformGEPs.hpp | 45 +++ 6 files changed, 411 insertions(+), 3 deletions(-) create mode 100644 subprojects/helper-to-tcg/src/PrepareForTcgPass/Transfo= rmGEPs.cpp create mode 100644 subprojects/helper-to-tcg/src/PrepareForTcgPass/Transfo= rmGEPs.hpp diff --git a/subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp b/subp= rojects/helper-to-tcg/include/PrepareForTcgPass.hpp index 3e0679b46c..d0cd6e3cbd 100644 --- a/subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp +++ b/subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp @@ -17,15 +17,18 @@ =20 #pragma once =20 +#include "DebugInfo.hpp" #include "TcgGlobalMap.hpp" #include =20 class PrepareForTcgPass : public llvm::PassInfoMixin { TcgGlobalMap &ResultTcgGlobalMap; + const DebugInfoMapTy &DebugInfo; =20 public: - PrepareForTcgPass(TcgGlobalMap &ResultTcgGlobalMap) - : ResultTcgGlobalMap(ResultTcgGlobalMap) {} + PrepareForTcgPass(TcgGlobalMap &ResultTcgGlobalMap, + const DebugInfoMapTy &DebugInfo) + : ResultTcgGlobalMap(ResultTcgGlobalMap), DebugInfo(DebugInfo) {} llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM); }; diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index c2926652f3..564191d328 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -45,6 +45,7 @@ sources =3D [ 'src/PrepareForOptPass/PrepareForOptPass.cpp', 'src/PseudoInst.cpp', 'src/PrepareForTcgPass/PrepareForTcgPass.cpp', + 'src/PrepareForTcgPass/TransformGEPs.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp index f24bb67f0c..9212bba29f 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -231,7 +231,7 @@ int main(int argc, char **argv) { // =20 TcgGlobalMap TcgGlobals; - MPM.addPass(PrepareForTcgPass(TcgGlobals)); + MPM.addPass(PrepareForTcgPass(TcgGlobals, DebugInfo)); MPM.addPass(VerifierPass()); { FunctionPassManager FPM; diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass= .cpp index 69add43529..10129fa245 100644 --- a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp @@ -17,6 +17,7 @@ =20 #include "PrepareForTcgPass.hpp" #include "CmdLineOptions.hpp" +#include "TransformGEPs.hpp" =20 #include #include @@ -136,5 +137,8 @@ PreservedAnalyses PrepareForTcgPass::run(Module &M, demotePhis(F); } const StringMap TypeIndexMap =3D collectTcgGlobals(M, ResultTc= gGlobalMap); + for (Function &F : M) { + transformGEPs(M, F, ResultTcgGlobalMap, TypeIndexMap, DebugInfo); + } return PreservedAnalyses::none(); } diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/TransformGEPs.= cpp b/subprojects/helper-to-tcg/src/PrepareForTcgPass/TransformGEPs.cpp new file mode 100644 index 0000000000..f4c4a5b22d --- /dev/null +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/TransformGEPs.cpp @@ -0,0 +1,355 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "TransformGEPs.hpp" +#include "DebugInfo.hpp" +#include "LlvmCompat.hpp" +#include "Error.hpp" +#include "PseudoInst.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_TYPE "transform-geps" + +using namespace llvm; + +// collectIndices will, given a getelementptr (GEP) instruction, construct= an +// array of GepIndex structs keeping track of the total offset into the st= ruct +// along with some access information. For instance, +// +// struct SubS { +// uint8_t a; +// uint8_t b; +// uint8_t c; +// }; +// +// struct S { +// uint64_t i; +// struct SubS sub[3]; +// }; +// +// void f(struct S *s, int idx) { +// S->sub[idx].a =3D ... +// S->sub[idx].b =3D ... +// S->sub[idx].c =3D ... +// } +// +// would correspond to the following GEPs +// +// getelementptr %struct.S, %struct.S* %s, i64 0, i32 1, %idx, i32 0 +// getelementptr %struct.S, %struct.S* %s, i64 0, i32 1, %idx, i32 1 +// getelementptr %struct.S, %struct.S* %s, i64 0, i32 1, %idx, i32 2 +// +// or the following GepIndex's +// +// GepIndex{Size=3D0,false}, GepIndex{Size=3D8,false}, GepIndex{Size=3D4= ,true}, +// GepIndex{Size=3D0,false} GepIndex{Size=3D0,false}, GepIndex{Size=3D8,= false}, +// GepIndex{Size=3D4,true}, GepIndex{Size=3D1,false} GepIndex{Size=3D0,f= alse}, +// GepIndex{Size=3D8,false}, GepIndex{Size=3D4,true}, GepIndex{Size=3D2,= false} +// + +struct GepIndex { + Value *V; + uint64_t Size; + bool IsArrayAccess =3D false; +}; + +using GepIndices =3D SmallVector; + +struct GlobalAccessInfo { + uint64_t Offset; + StringRef BaseTypeName; + Value *LastArrayIndex; +}; + +using GlobalAccessMap =3D DenseMap; + +static Expected collectIndices(const DataLayout &DL, + GEPOperator *Gep) { + Type *PtrOpTy =3D Gep->getPointerOperandType(); + if (!PtrOpTy->isPointerTy()) { + return mkError("GEPs on vectors are not handled!"); + } + Type *InternalTy =3D Type::getIntNTy(Gep->getContext(), 64); + auto *One =3D ConstantInt::get(InternalTy, 1u); + + GepIndices Result; + Type *CurrentTy =3D PtrOpTy; + + // Handle initial pointer dereference + auto Begin =3D Gep->idx_begin(); + { + CurrentTy =3D Gep->getSourceElementType(); + const size_t FixedSize =3D compat::getTypeAllocSize(DL, CurrentTy); + Result.push_back(GepIndex{*Begin, FixedSize}); + ++Begin; + } + + for (auto &Arg : make_range(Begin, Gep->idx_end())) { + switch (CurrentTy->getTypeID()) { + case Type::ArrayTyID: { + CurrentTy =3D cast(CurrentTy)->getElementType(); + const size_t FixedSize =3D compat::getTypeAllocSize(DL, Curren= tTy); + Result.push_back( + GepIndex{Arg.get(), FixedSize, /* IsArrayAccess=3D */ true= }); + } break; + case Type::StructTyID: { + auto *StructTy =3D cast(CurrentTy); + auto *Constant =3D dyn_cast(Arg.get()); + if (Constant->getBitWidth() > DL.getPointerSizeInBits()) { + return mkError( + "GEP to struct with unsupported index bit width!"); + } + uint64_t ConstantValue =3D Constant->getZExtValue(); + uint64_t ElementOffset =3D + DL.getStructLayout(StructTy)->getElementOffset(ConstantVal= ue); + CurrentTy =3D StructTy->getTypeAtIndex(ConstantValue); + Result.push_back(GepIndex{One, ElementOffset}); + } break; + default: + return mkError("GEP unsupported index type: "); + } + } + + return Result; +} + +// Takes indices associated with a getelementpointer instruction and expan= ds +// it into pointer math. +static void replaceGEPWithPointerMath(Module &M, Instruction *ParentInst, + GEPOperator *Gep, + const GepIndices &Indices) { + assert(Indices.size() > 0); + IRBuilder<> Builder(ParentInst); + Value *PtrOp =3D Gep->getPointerOperand(); + + // Sum indices to get the total offset from the base pointer + Value *PrevV =3D nullptr; + for (auto &Index : Indices) { + Value *Mul =3D Builder.CreateMul( + Index.V, ConstantInt::get(Index.V->getType(), Index.Size)); + if (PrevV) { + uint32_t BitWidthLeft =3D + cast(PrevV->getType())->getIntegerBitWidth(); + uint32_t BitWidthRight =3D + cast(Mul->getType())->getIntegerBitWidth(); + if (BitWidthLeft < BitWidthRight) { + PrevV =3D Builder.CreateZExt(PrevV, Mul->getType()); + } else if (BitWidthLeft > BitWidthRight) { + Mul =3D Builder.CreateZExt(Mul, PrevV->getType()); + } + PrevV =3D Builder.CreateAdd(PrevV, Mul); + } else { + PrevV =3D Mul; + } + } + + Gep->replaceAllUsesWith(createPseudoInstCall( + M, Builder, PtrAdd, Gep->getType(), {PtrOp, PrevV})); +} + +// Takes indices associated with a getelementpointer instruction and expan= ds +// it into pointer math. +static Value *replaceGEPWithGlobalAccess(Module &M, Instruction *ParentIns= t, + GEPOperator *Gep, size_t TypeInde= x, + uint64_t BaseOffset, + Value *ArrayIndex) { + CallInst *Call; + IRBuilder<> Builder(ParentInst); + Type *IndexTy =3D Type::getIntNTy(M.getContext(), 64); + auto *ConstBaseOffset =3D ConstantInt::get(IndexTy, BaseOffset); + auto *ConstTypeIndex =3D ConstantInt::get(IndexTy, TypeIndex); + if (ArrayIndex) { + Call =3D + createPseudoInstCall(M, Builder, AccessGlobalArray, Gep->getTy= pe(), + {ConstTypeIndex, ConstBaseOffset, ArrayIn= dex}); + } else { + Call =3D + createPseudoInstCall(M, Builder, AccessGlobalValue, Gep->getTy= pe(), + {ConstTypeIndex, ConstBaseOffset}); + } + Gep->replaceAllUsesWith(Call); + return cast(Call); +} + +static bool transformGEP(Module &M, const TcgGlobalMap &TcgGlobals, + GlobalAccessMap &GAMap, + const StringMap &TypeIndexMap, + const DebugInfoMapTy &DebugInfo, + const GepIndices &Indices, Instruction *ParentIns= t, + GEPOperator *Gep) { + GlobalAccessInfo Info{}; + uint32_t NumArrayAccesses =3D 0; + for (const GepIndex &Index : Indices) { + if (Index.IsArrayAccess) { + Info.LastArrayIndex =3D Index.V; + ++NumArrayAccesses; + } else if (auto *Const =3D dyn_cast(Index.V)) { + Info.Offset +=3D Const->getZExtValue() * Index.Size; + } + } + + Value *PtrOp =3D Gep->getPointerOperand(); + bool IsGlobalAccess =3D isa(PtrOp); + if (auto It =3D GAMap.find(PtrOp); It !=3D GAMap.end()) { + Info.Offset +=3D It->second.Offset; + Info.BaseTypeName =3D It->second.BaseTypeName; + assert(!Info.LastArrayIndex or !It->second.LastArrayIndex); + if (It->second.LastArrayIndex) { + Info.LastArrayIndex =3D It->second.LastArrayIndex; + } + IsGlobalAccess =3D true; + } else if (auto It =3D DebugInfo.find(PtrOp); It !=3D DebugInfo.end())= { + Info.BaseTypeName =3D It->second.BaseTypeName; + } + + bool PtrHasMapping =3D + !Info.BaseTypeName.empty() and TypeIndexMap.count(Info.BaseTypeNam= e); + + LLVM_DEBUG({ + dbgs() << "For " << *Gep << "\n"; + dbgs() << " has mapping: " << PtrHasMapping << "\n"; + dbgs() << " is global access: " << IsGlobalAccess << "\n"; + }); + + if (IsGlobalAccess and PtrHasMapping and NumArrayAccesses <=3D 1) { + + if (!isa(Gep)) { + bool HasOnlyGEPUsers =3D true; + for (auto *U : cast(Gep)->users()) { + if (!isa(U)) { + HasOnlyGEPUsers =3D false; + break; + } + } + if (HasOnlyGEPUsers) { + GAMap[cast(Gep)] =3D Info; + return true; + } + } + + const size_t Index =3D TypeIndexMap.lookup(Info.BaseTypeName); + + // Array accesses, particularly those to an array at the beginning= of a + // mapped structs, e.g. `uint32_t v =3D env->gpr[40]`, might appea= r either + // as + // + // getelementptr struct.CPUArchState, ptr %0, i64 0, i64 40, + // + // or + // + // getelementptr i8, ptr %0, i64 160. + // + // The former and simpler one being more common in older LLVM vers= ions. + // For the latter we need to manually compute the array index. + for (auto &P : TcgGlobals[Index]) { + const TcgGlobal Global =3D P.second; + if ((Global.NumElements =3D=3D 1 and Info.Offset =3D=3D P.firs= t) or + (Info.Offset >=3D P.first and + Info.Offset < P.first + Global.NumElements * Global.Strid= e)) { + Value *ArrayIndexV =3D Info.LastArrayIndex; + if (Global.NumElements > 1 and !Info.LastArrayIndex) { + assert(Global.Stride > 0); + uint64_t ArrayIndex =3D + (Info.Offset - P.first) / Global.Stride; + Info.Offset =3D P.first; + ArrayIndexV =3D ConstantInt::get( + Type::getInt64Ty(M.getContext()), ArrayIndex); + } + + LLVM_DEBUG(dbgs() << " replacing with global access\n"); + Value *Access =3D replaceGEPWithGlobalAccess( + M, ParentInst, Gep, Index, Info.Offset, ArrayIndexV); + GAMap[Access] =3D Info; + return !isa(Gep); + } + } + } + + LLVM_DEBUG(dbgs() << " replacing with pointer math\n"); + replaceGEPWithPointerMath(M, ParentInst, Gep, Indices); + return !isa(Gep); +} + +static GEPOperator *getGEPOperator(Instruction *I) { + // If the instructions is directly a GEP, simply return it. + auto *GEP =3D dyn_cast(I); + if (GEP) { + return GEP; + } + + // Hard-code handling of GEPs that appear as an inline operand to loads + // and stores. + if (isa(I)) { + auto *Load =3D cast(I); + auto *ConstExpr =3D dyn_cast(Load->getPointerOperand= ()); + if (ConstExpr) { + return dyn_cast(ConstExpr); + } + } else if (isa(I)) { + auto *Store =3D dyn_cast(I); + auto *ConstExpr =3D dyn_cast(Store->getPointerOperan= d()); + if (ConstExpr) { + return dyn_cast(ConstExpr); + } + } + + return nullptr; +} + +void transformGEPs(Module &M, Function &F, const TcgGlobalMap &TcgGlobals, + const StringMap &TypeIndexMap, + const DebugInfoMapTy &DebugInfo) { + SmallSet InstToErase; + GlobalAccessMap GAMap; + + LLVM_DEBUG(dbgs() << "Transforming GEPs for:" << F.getName() << "\n"); + + for (auto &I : instructions(F)) { + GEPOperator *GEP =3D getGEPOperator(&I); + if (!GEP) { + continue; + } + + Expected Indices =3D collectIndices(M.getDataLayout(),= GEP); + if (!Indices) { + dbgs() << "Failed collecting GEP indices for:\n\t" << I << "\n= "; + dbgs() << "Reason: " << Indices.takeError(); + abort(); + } + + bool ShouldErase =3D transformGEP(M, TcgGlobals, GAMap, TypeIndexM= ap, + DebugInfo, Indices.get(), &I, GEP); + if (ShouldErase) { + InstToErase.insert(&I); + } + } + + for (auto *I : InstToErase) { + I->eraseFromParent(); + } +} diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/TransformGEPs.= hpp b/subprojects/helper-to-tcg/src/PrepareForTcgPass/TransformGEPs.hpp new file mode 100644 index 0000000000..8430a65fa0 --- /dev/null +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/TransformGEPs.hpp @@ -0,0 +1,45 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include "DebugInfo.hpp" +#include "TcgGlobalMap.hpp" +#include +#include +#include + +// +// Transform of module that converts `getelementptr` (GEP) operators to +// pseudo instructions, either: +// +// 1. `call @AccessGlobalArray(StructIndex, Offset, Index)` +// if `Offset` is mapped to a global TCG array; +// +// 2. `call @AccessGlobalValue(StructIndex, Offset)` +// if `Offset` is mapped to a global TCG value; +// +// 3. Pointer math, if above fails. +// +// `StructIndex` is a an increasing integer assigned to each mapped struct= type, +// usually only `CPUArchState` is mapped, so `StructIndex` would be 0. +// + +void transformGEPs(llvm::Module &M, llvm::Function &F, + const TcgGlobalMap &TcgGlobals, + const llvm::StringMap &TypeIndexMap, + const DebugInfoMapTy &DebugInfo); --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381122; cv=none; d=zohomail.com; s=zohoarc; b=T0EgPyMkQaNufilx+5iGf46KgwSxv6b6XqNRqS7Jhi4/0ClU3Z1XiN3ZEUmPVHZUk4YJ+kNFGRuhgch92hMXj/BnDDm3IhbfiSYJOAz0poHUCUVyYUqUuXtXORREpJLUOBJYwn5kFycU5Gs4wzV1Q89z7WZGu3ePCCE9VxDz3kQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381122; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=FLyb39kl99ghSZ0FHAf6am18rC23pEPnR/JAPrlXboA=; b=ckRj5YeWHRvmYHx5lYhYsRUZd9YSyPO13jYF2JgHvElfYw6VxJzfrds0sBJl5wM8pQUmRRWnqiLpC+x2OaeculIBTd0QxZiCg4bC1mWTtjlPuFbGiCMPQ7Wz1SQ+8tj4ua6JGpM7FPZq/eKDt4Gjs16DDW0+zuy7g1mZMCQthvE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381122399160.5772996668079; Wed, 29 Jul 2026 20:12:02 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH70-00044C-7I; Wed, 29 Jul 2026 23:07:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6r-0003yt-Dj for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:01 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6k-0002x7-T2 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=FLyb39kl99ghSZ0FHAf6am18rC23pEPnR/JAPrlXboA=; b=SzsQfJbPtDY4Hgs F08toIHpzbDypQoT9bNqdDn2V+gvAVDJTTDlEDUj2Xj/K0lSlxah6N17fFob7wiCgWxWYmdvw9POt S/3lingoXVEBzPrH9szpBggFUODMetw1iZPhqiBqSRs1OpiyqytJQWGt9lT6skqspC5VU35juw4Oo vs=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 27/50] helper-to-tcg: PrepareForTcgPass, canonicalize IR Date: Thu, 30 Jul 2026 05:10:01 +0200 Message-ID: <20260730031025.12926-28-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381124135158500 Content-Type: text/plain; charset="utf-8" Iterates over the IR with the goal of converting it to a form closer to TCG, taking care of IR discrepancies between LLVM and TCG. This also simplifies the backend by containing the bulk of custom IR transformations. Signed-off-by: Anton Johansson --- .../helper-to-tcg/include/CmdLineOptions.hpp | 3 + .../include/PrepareForTcgPass.hpp | 7 +- subprojects/helper-to-tcg/meson.build | 1 + subprojects/helper-to-tcg/src/Pipeline.cpp | 63 +- .../src/PrepareForTcgPass/CanonicalizeIR.cpp | 1193 +++++++++++++++++ .../src/PrepareForTcgPass/CanonicalizeIR.hpp | 24 + .../PrepareForTcgPass/PrepareForTcgPass.cpp | 2 + 7 files changed, 1290 insertions(+), 3 deletions(-) create mode 100644 subprojects/helper-to-tcg/src/PrepareForTcgPass/Canonic= alizeIR.cpp create mode 100644 subprojects/helper-to-tcg/src/PrepareForTcgPass/Canonic= alizeIR.hpp diff --git a/subprojects/helper-to-tcg/include/CmdLineOptions.hpp b/subproj= ects/helper-to-tcg/include/CmdLineOptions.hpp index bfdd3ebe41..3a827f8ab7 100644 --- a/subprojects/helper-to-tcg/include/CmdLineOptions.hpp +++ b/subprojects/helper-to-tcg/include/CmdLineOptions.hpp @@ -25,3 +25,6 @@ extern llvm::cl::list InputFiles; extern llvm::cl::opt TranslateAllHelpers; // Options for PrepareForTcgPass extern llvm::cl::opt TcgGlobalMappingsName; +extern llvm::cl::opt UserPCRelBranchFunc; +extern llvm::cl::opt UserPCRelBranchFallthroughFunc; +extern llvm::cl::opt UserPCRelBranchConditionalFunc; diff --git a/subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp b/subp= rojects/helper-to-tcg/include/PrepareForTcgPass.hpp index d0cd6e3cbd..078477ba2f 100644 --- a/subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp +++ b/subprojects/helper-to-tcg/include/PrepareForTcgPass.hpp @@ -19,16 +19,19 @@ =20 #include "DebugInfo.hpp" #include "TcgGlobalMap.hpp" +#include "VectorLayout.hpp" #include =20 class PrepareForTcgPass : public llvm::PassInfoMixin { TcgGlobalMap &ResultTcgGlobalMap; const DebugInfoMapTy &DebugInfo; + const VectorLayout &VL; =20 public: PrepareForTcgPass(TcgGlobalMap &ResultTcgGlobalMap, - const DebugInfoMapTy &DebugInfo) - : ResultTcgGlobalMap(ResultTcgGlobalMap), DebugInfo(DebugInfo) {} + const DebugInfoMapTy &DebugInfo, const VectorLayout = &VL) + : ResultTcgGlobalMap(ResultTcgGlobalMap), DebugInfo(DebugInfo), VL= (VL) { + } llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM); }; diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 564191d328..79ce0c6dd8 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -46,6 +46,7 @@ sources =3D [ 'src/PseudoInst.cpp', 'src/PrepareForTcgPass/PrepareForTcgPass.cpp', 'src/PrepareForTcgPass/TransformGEPs.cpp', + 'src/PrepareForTcgPass/CanonicalizeIR.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp index 9212bba29f..9b45664bdc 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -19,6 +19,7 @@ #include "LlvmCompat.hpp" #include "PrepareForOptPass.hpp" #include "PrepareForTcgPass.hpp" +#include "VectorLayout.hpp" =20 #if LLVM_VERSION_MAJOR =3D=3D 15 #include @@ -42,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +82,51 @@ cl::opt TcgGlobalMappingsName( "into a struct to TCG globals"), cl::init("mappings"), cl::cat(Cat)); =20 +cl::opt UserPCRelBranchFunc( + "user-pcrel-branch-func", + cl::desc("Specify a function name in the input which represents a " + "PC-relative jump operation in QEMU."), + cl::init(""), cl::cat(Cat)); + +cl::opt UserPCRelBranchConditionalFunc( + "user-pcrel-branch-conditional-func", + cl::desc("Specify a function name in QEMU which represents a " + "PC-relative conditional jump operation. Will be" + " emitted when the function supplied with -user-pcrel-branch-= func" + " is called from inside a conditional block."), + cl::init(""), cl::cat(Cat)); + +cl::opt UserPCRelBranchFallthroughFunc( + "user-pcrel-branch-fallthrough-func", + cl::desc("Specify a function name in QEMU which represents a " + "PC-relative fallthrough operation. Will be emitted when the" + " function supplied with -user-pcrel-branch-func" + " is called" + " from inside a conditional block, but that condition isn't t= aken." + " and we instead need to fallthrough to the next instruction.= "), + cl::init(""), cl::cat(Cat)); +=20 +static llvm::cl::opt VecForceBigEndian( + "vec-force-big-endian", + cl::desc("Force emission of vector operations as if on a big-endian ho= st."), + cl::init(false), cl::cat(Cat)); + +static llvm::cl::opt + VecBlockBytes("vec-block-bytes", + cl::desc("Sets the size of the host-endian blocks vector= " + "used to represent target vectors."), + cl::init(64), cl::cat(Cat)); + +static llvm::cl::opt VecLane0( + "vec-lane-0", + cl::desc("Set whether lane 0 is treated as the high- or low-end " + "bytes of the vector blocks ([most|least]-significant)."), + cl::values(clEnumVal(LeastSignificant, + "Vector lane 0 is in the least-significant bytes"= ), + clEnumVal(MostSignificant, + "Vector lane 0 is in the most-significant bytes")= ), + cl::init(LeastSignificant), cl::cat(Cat)); + // Define a TargetTransformInfo (TTI) subclass, this allows for overriding // common per-llvm-target information expected by other LLVM passes, such // as the width of the largest scalar/vector registers. Needed for consis= tent @@ -146,10 +193,24 @@ int main(int argc, char **argv) { } #endif =20 + if (!isPowerOf2_32(VecBlockBytes) or VecBlockBytes < 8) { + errs() << "--" << VecBlockBytes.ArgStr + << " must be a power-of-two and at least 8 bytes."; + return 1; + } + LLVMContext Context; SMDiagnostic Err; std::unique_ptr M =3D parseIRFile(InputFile, Err, Context); =20 + // After we have a module we can get the data layout and determine host + // endianness. + VectorLayout VL =3D { + .HostBigEndian =3D VecForceBigEndian or M->getDataLayout().isBigEn= dian(), + .Lane0 =3D VecLane0, + .BlockBytes =3D VecBlockBytes, + }; + // Create a new TargetMachine to represent a TCG target, // we use x86_64 as a base and derive from that using a // TargetTransformInfo to provide allowed scalar and vector @@ -231,7 +292,7 @@ int main(int argc, char **argv) { // =20 TcgGlobalMap TcgGlobals; - MPM.addPass(PrepareForTcgPass(TcgGlobals, DebugInfo)); + MPM.addPass(PrepareForTcgPass(TcgGlobals, DebugInfo, VL)); MPM.addPass(VerifierPass()); { FunctionPassManager FPM; diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/CanonicalizeIR= .cpp b/subprojects/helper-to-tcg/src/PrepareForTcgPass/CanonicalizeIR.cpp new file mode 100644 index 0000000000..54fdcade4e --- /dev/null +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/CanonicalizeIR.cpp @@ -0,0 +1,1193 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "CanonicalizeIR.hpp" +#include "CmdLineOptions.hpp" +#include "LlvmCompat.hpp" +#include "PseudoInst.hpp" +#include "VectorLayout.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // for std::max/min + +using namespace llvm; +using namespace PatternMatch; + +// Needed to track and remove instructions not handled by a subsequent dea= d code +// elimination, this applies to calls to pseudo instructions in particular. +using EraseInstVec =3D SmallVector; +using UsageCountMap =3D DenseMap; +using ExitSet =3D SmallSet; + +// Helper function to remove an instruction only if all uses have been rem= oved. +// This way we can keep track instruction uses without having to modify th= e IR, +// or without having to iterate over all uses everytime we wish to remove = an +// instruction. +static void addToEraseVectorIfUnused(EraseInstVec &InstToErase, + UsageCountMap &UsageMap, Value *V) { + auto *I =3D dyn_cast(V); + if (!I) { + return; + } + + // Add V to map if not there + if (UsageMap.count(V) =3D=3D 0) { + UsageMap[V] =3D V->getNumUses(); + } + + // Erase if count reaches zero + if (--UsageMap[V] =3D=3D 0) { + InstToErase.push_back(I); + UsageMap.erase(V); + } +} + +// Forward declarations of IR transformations used in canonicalizing the IR +static void upcastAshr(Instruction *I); +static void convertInsertShuffleToSplat(EraseInstVec &InstToErase, + UsageCountMap &UsageMap, Module &M, + Instruction *I); + +static void +defineVectorConstants(Module &M, const VectorLayout &VL, Instruction *I, + DenseMap &Replacements); + +static void simplifyVecBinOpWithSplat(EraseInstVec &InstToErase, + UsageCountMap &UsageMap, Module &M, + BinaryOperator *BinOp); + +static void convertSelectICmp(Module &M, SelectInst *Select, ICmpInst *ICm= p); + +static void convertQemuLoadStoreToPseudoInst(Module &M, CallInst *Call, + EraseInstVec &InstToErase, + UsageCountMap &UsageMap); +static void convertExceptionCallsToPseudoInst(Module &M, CallInst *Call); +static void convertReturnAddrToPseudoInst(Module &M, CallInst *Call); +static void convertImmediateSelectAccessGlobal(EraseInstVec &InstToErase, + Module &M, CallInst *Call); +static void convertImmediateDeclCall(EraseInstVec &InstToErase, Module &M, + CallInst *Call); +static void convertUserBranchInstructions(Module &M, + DominatorTreeAnalysis::Result &D= T, + const ExitSet &Exits, CallInst *= Call); +static void convertVecStoreToPseudoInst(EraseInstVec &InstToErase, Module = &M, + StoreInst *Store); + +void canonicalizeIR(Module &M, ModuleAnalysisManager &MAM, + const VectorLayout &VL) { + auto &FAM =3D + MAM.getResult(M).getManager(); + const bool HasUserBranches =3D !UserPCRelBranchFunc.empty() and + !UserPCRelBranchConditionalFunc.empty() a= nd + !UserPCRelBranchFallthroughFunc.empty(); + for (Function &F : M) { + if (F.isDeclaration()) { + continue; + } + + EraseInstVec InstToErase; + UsageCountMap UsageMap; + ExitSet Exits; + auto &DT =3D FAM.getResult(F); + + // Collect basic blocks which exit the function, needed to support + // user-supplied branch calls, and correctly handle conditional br= anches + if (HasUserBranches) { + for (auto &BB : F) { + if (isa(BB.getTerminator())) { + Exits.insert(&BB); + } + } + } + + SmallPtrSet ReplacedVectorConstants; + + // Perform a first pass over all instructions in the function and = apply + // IR transformations sequentially. NOTE: order matters here. + for (Instruction &I : instructions(F)) { + if (I.isArithmeticShift()) { + upcastAshr(&I); + } + + convertInsertShuffleToSplat(InstToErase, UsageMap, M, &I); + + // Depends on convertInsertShuffleToSplat for @VecSplat instru= ctions + if (auto *BinOp =3D dyn_cast(&I)) { + simplifyVecBinOpWithSplat(InstToErase, UsageMap, M, BinOp); + } + + // Independent of above + if (auto *ICmp =3D dyn_cast(&I)) { + for (auto *U : ICmp->users()) { + auto *Select =3D dyn_cast(U); + if (Select and Select->getCondition() =3D=3D ICmp) { + convertSelectICmp(M, Select, ICmp); + } + } + } + + // Independent of above, can run at any point + if (auto *Call =3D dyn_cast(&I)) { + convertQemuLoadStoreToPseudoInst(M, Call, InstToErase, + UsageMap); + convertExceptionCallsToPseudoInst(M, Call); + convertReturnAddrToPseudoInst(M, Call); + convertImmediateSelectAccessGlobal(InstToErase, M, Call); + convertImmediateDeclCall(InstToErase, M, Call); + if (HasUserBranches) { + convertUserBranchInstructions(M, DT, Exits, Call); + } + } + + // Depends on other vector conversions performed above, needs = to + // run last + if (auto *Store =3D dyn_cast(&I)) { + convertVecStoreToPseudoInst(InstToErase, M, Store); + } + } + + // Finally clean up instructions we need to remove manually + for (Instruction *I : InstToErase) { + I->eraseFromParent(); + } + + DenseMap Replacements; + for (Instruction &I : instructions(F)) { + defineVectorConstants(M, VL, &I, Replacements); + } + } +} + +static Value *upcastInt(IRBuilder<> &Builder, IntegerType *FinalIntTy, + Value *V) { + if (auto *ConstInt =3D dyn_cast(V)) { + return ConstantInt::get(FinalIntTy, ConstInt->getZExtValue()); + } else { + return Builder.CreateSExt(V, FinalIntTy); + } +} + +// Convert +// +// %2 =3D ashr i[8|16] %1, %0 +// +// to +// +// %2 =3D zext i[8|16] %1 to i32 +// %3 =3D zext i[8|16] %2 to i32 +// %2 =3D ashr i32 %2, %3 +// +static void upcastAshr(Instruction *I) { + // Only care about scalar shifts < on less than 32-bit integers + auto *IntTy =3D dyn_cast(I->getType()); + if (!IntTy or IntTy->getBitWidth() >=3D 32) { + return; + } + + IRBuilder<> Builder(I); + + Value *Op1 =3D I->getOperand(0); + Value *Op2 =3D I->getOperand(1); + auto *UpcastIntTy =3D Builder.getInt32Ty(); + Op1 =3D upcastInt(Builder, UpcastIntTy, Op1); + Op2 =3D upcastInt(Builder, UpcastIntTy, Op2); + + auto *AShr =3D Builder.CreateAShr(Op1, Op2); + auto *Trunc =3D Builder.CreateTrunc(AShr, I->getType()); + I->replaceAllUsesWith(Trunc); +} + +// Convert vector intrinsics +// +// %0 =3D insertelement ... +// %1 =3D shuffle ... +// +// to +// +// %0 =3D call @VecSplat.* +// +static void convertInsertShuffleToSplat(EraseInstVec &InstToErase, + UsageCountMap &UsageMap, Module &M, + Instruction *I) { + Value *SplatV; + if (match(I, compat_m_Shuffle(compat_m_InsertElt(m_Value(), m_Value(Sp= latV), + m_ZeroInt()), + m_Value(), compat_m_ZeroMask()))) { + auto *VecTy =3D cast(I->getType()); + IRBuilder<> Builder(I); + I->replaceAllUsesWith( + createPseudoInstCall(M, Builder, VecSplat, VecTy, {SplatV})); + addToEraseVectorIfUnused(InstToErase, UsageMap, I->getOperand(0)); + InstToErase.push_back(I); + } +} + +static void +defineVectorConstants(Module &M, const VectorLayout &VL, Instruction *I, + DenseMap &Replacements) { + for (size_t J =3D 0; J < I->getNumOperands(); ++J) { + Value *Op =3D I->getOperand(J); + auto *Const =3D dyn_cast(Op); + auto *VecTy =3D dyn_cast(Op->getType()); + if (!Const or !VecTy) { + // Only care about non-splatted constant vectors, skip + // everything else. + continue; + } + + if (Replacements.count(Const)) { + I->setOperand(J, Replacements[Const]); + continue; + } + + if (Value *Splat =3D Const->getSplatValue()) { + auto *VecTy =3D cast(Const->getType()); + IRBuilder<> Builder(I); + CallInst *Call =3D + createPseudoInstCall(M, Builder, VecSplat, VecTy, {Splat}); + I->setOperand(J, Call); + Replacements[Const] =3D Call; + } else { + // Constant non-splatted vector, attempt to combine elements + // to make it splattable. + SmallVector Ints; + + // Copy over elements to a vector + const unsigned ElementCount =3D compat::getVectorElementCount(= VecTy); + const unsigned ElementSize =3D + VecTy->getElementType()->getIntegerBitWidth(); + + for (unsigned I =3D 0; I < ElementCount; ++I) { + Constant *Element =3D Const->getAggregateElement(I); + uint64_t Value =3D Element->getUniqueInteger().getZExtValu= e(); + Ints.push_back(Value); + } + + // When combining adjacent elements, the maximum size supported + // by TCG is 64-bit. MaxNumElements is the maximum amount of + // elements to attempt to merge + size_t PatternLen =3D 0; + const unsigned MaxNumElements =3D 8 * sizeof(uint64_t) / Eleme= ntSize; + for (unsigned N =3D MaxNumElements; N > 1; N /=3D 2) { + // Attempt to combine N elements by checking if the first + // N elements tile the vector. + bool Match =3D true; + for (unsigned J =3D 0; J < ElementCount; ++J) { + if (Ints[J % N] !=3D Ints[J]) { + Match =3D false; + break; + } + } + // If tiling succeeded, break out + if (Match) { + PatternLen =3D N; + break; + } + } + + if (PatternLen > 0) { + // Managed to tile vector with splattable element, compute + // final splattable value + // TODO: Move to VectorLayout.hpp + uint64_t Column =3D 0; + for (unsigned I =3D 0; I < PatternLen; ++I) { + // Flips the indices if lane 0 is in the most-signific= ant + // bits. + const size_t Index =3D VL.indexLane(PatternLen, 0, I); + Column |=3D Ints[Index] << I * ElementSize; + } + IRBuilder<> Builder(I); + CallInst *Call =3D createPseudoInstCall( + M, Builder, VecSplat, VecTy, {Builder.getInt64(Column)= }); + I->setOperand(J, Call); + Replacements[Const] =3D Call; + } else { + // Tiling failed, fall back to emitting an array copy from + // C to a gvec vector. + // TODO: Move to VectorLayout.hpp + IRBuilder<> Builder(I); + SmallVector Columns; + const size_t VectorSize =3D + (ElementCount * (ElementSize / 8) + 7); + const size_t ColumnCount =3D VectorSize / 8; + Columns.resize(ColumnCount); + for (size_t C =3D 0; C < ColumnCount; ++C) { + uint64_t Column =3D 0; + const size_t LanesPerColumn =3D 64 / ElementSize; + for (size_t L =3D 0; L < LanesPerColumn; ++L) { + const size_t Index =3D VL.indexLane(LanesPerColumn= , C, L); + Column |=3D Ints[Index] << (ElementSize * L); + } + assert(VL.BlockBytes >=3D 8); + const size_t Size =3D + std::min(ColumnCount, VL.BlockBytes / 8); + const size_t Index =3D VL.indexBlock(Size, C); + Columns[Index] =3D Builder.getInt64(Column); + } + CallInst *Call =3D + createPseudoInstCall(M, Builder, VecConstant, VecTy, + {ConstantVector::get(Columns)}); + I->setOperand(J, Call); + Replacements[Const] =3D Call; + } + } + } +} + +// Convert +// +// %1 =3D @VecSplat(%0) +// %2 =3D ... op %1 +// +// to +// +// %2 =3D call @Vec[op]Scalar(..., %0) +// +// which more closely matches TCG gvec operations. +static void simplifyVecBinOpWithSplat(EraseInstVec &InstToErase, + UsageCountMap &UsageMap, Module &M, + BinaryOperator *BinOp) { + Value *Lhs =3D BinOp->getOperand(0); + Value *Rhs =3D BinOp->getOperand(1); + if (!Lhs->getType()->isVectorTy() or !Rhs->getType()->isVectorTy()) { + return; + } + + // Get splat value from constant or @VecSplat call + Value *SplatValue =3D nullptr; + if (auto *Const =3D dyn_cast(Rhs)) { + SplatValue =3D Const->getSplatValue(); + } else if (auto *Call =3D dyn_cast(Rhs)) { + if (getPseudoInstFromCall(Call) =3D=3D VecSplat) { + SplatValue =3D Call->getOperand(0); + } + } + + if (SplatValue =3D=3D nullptr) { + return; + } + + auto *VecTy =3D cast(Lhs->getType()); + auto *ConstInt =3D dyn_cast(SplatValue); + bool ConstIsNegOne =3D ConstInt and ConstInt->getSExtValue() =3D=3D -1; + bool IsNot =3D BinOp->getOpcode() =3D=3D Instruction::Xor and ConstIsN= egOne; + if (IsNot) { + IRBuilder<> Builder(BinOp); + BinOp->replaceAllUsesWith( + createPseudoInstCall(M, Builder, VecNot, VecTy, {Lhs})); + } else { + PseudoInst Inst; + switch (BinOp->getOpcode()) { + case Instruction::Add: + Inst =3D VecAddScalar; + break; + case Instruction::Sub: + Inst =3D VecSubScalar; + break; + case Instruction::Mul: + Inst =3D VecMulScalar; + break; + case Instruction::Xor: + Inst =3D VecXorScalar; + break; + case Instruction::Or: + Inst =3D VecOrScalar; + break; + case Instruction::And: + Inst =3D VecAndScalar; + break; + case Instruction::Shl: + Inst =3D VecShlScalar; + break; + case Instruction::LShr: + Inst =3D VecLShrScalar; + break; + case Instruction::AShr: + Inst =3D VecAShrScalar; + break; + default: + abort(); + } + + IRBuilder<> Builder(BinOp); + // Scalar gvec shift operations uses 32-bit scalars, whereas arith= metic + // operations uses 64-bit scalars. + uint32_t SplatSize =3D SplatValue->getType()->getIntegerBitWidth(); + if (BinOp->isShift()) { + if (SplatSize > 32) { + SplatValue =3D + Builder.CreateTrunc(SplatValue, Builder.getInt32Ty()); + } + } else { + if (SplatSize < 64) { + SplatValue =3D + Builder.CreateZExt(SplatValue, Builder.getInt64Ty()); + } + } + BinOp->replaceAllUsesWith( + createPseudoInstCall(M, Builder, Inst, VecTy, {Lhs, SplatValue= })); + } + + InstToErase.push_back(BinOp); + addToEraseVectorIfUnused(InstToErase, UsageMap, Rhs); +} + +// Convert +// +// %2 =3D icmp [sgt|ugt|slt|ult] %0, %1 +// %5 =3D select %2, %3, %4 +// +// to +// +// %5 =3D [s|u][max|min] %0, %1 +// +// if possible. Results in cleaner IR, particularly useful for vector +// instructions. +static bool convertSelectICmpToMinMax(Module &M, SelectInst *Select, + ICmpInst *ICmp, ICmpInst::Predicate = &Pred, + Value *ICmpOp0, Value *ICmpOp1, + Value *SelectOp0, Value *SelectOp1) { + if (ICmpOp0 !=3D SelectOp0 or ICmpOp1 !=3D SelectOp1) { + return false; + } + + Intrinsic::ID Intrin; + switch (Pred) { + case ICmpInst::ICMP_SGT: + Intrin =3D Intrinsic::smax; + break; + case ICmpInst::ICMP_UGT: + Intrin =3D Intrinsic::umax; + break; + case ICmpInst::ICMP_SLT: + Intrin =3D Intrinsic::smin; + break; + case ICmpInst::ICMP_ULT: + Intrin =3D Intrinsic::umin; + break; + default: + return false; + } + + auto Ty =3D Select->getType(); + auto MaxMinF =3D compat::Intrinsic::getOrInsertDeclaration(&M, Intrin,= {Ty}); + + IRBuilder<> Builder(Select); + auto Call =3D Builder.CreateCall(MaxMinF, {ICmpOp0, ICmpOp1}); + Select->replaceAllUsesWith(Call); + + return true; +} + +// In LLVM, icmp on vectors returns a vector on i1s whereas TCGs gvec_cmp +// returns a vector of the element type of its operands. This can result = in +// some subtle bugs. Convert +// +// icmp -> call @VecCompare +// select -> call @VecWideCondBitsel +// +static bool convertSelectICmpToVecBitsel(Module &M, SelectInst *Select, + ICmpInst *ICmp, + ICmpInst::Predicate &Pred, + Value *ICmpOp0, Value *ICmpOp1, + Value *SelectOp0, Value *SelectOp= 1) { + auto *ICmpVecTy =3D dyn_cast(ICmpOp0->getType()); + auto *SelectVecTy =3D dyn_cast(Select->getType()); + if (!ICmpVecTy or !SelectVecTy) { + return false; + } + + Instruction *Cmp =3D ICmp; + { + IRBuilder<> Builder(Cmp); + ICmpInst::Predicate Pred =3D ICmp->getPredicate(); + CallInst *Call =3D createPseudoInstCall( + M, Builder, VecCompare, ICmpVecTy, + {ConstantInt::get(Builder.getInt32Ty(), Pred), ICmpOp0, ICmpOp= 1}); + Cmp =3D Call; + } + + unsigned SrcWidth =3D ICmpVecTy->getElementType()->getIntegerBitWidth(= ); + unsigned DstWidth =3D SelectVecTy->getElementType()->getIntegerBitWidt= h(); + + IRBuilder<> Builder(Select); + if (SrcWidth < DstWidth) { + Cmp =3D cast(Builder.CreateSExt(Cmp, SelectVecTy)); + } else if (SrcWidth > DstWidth) { + Cmp =3D cast(Builder.CreateTrunc(Cmp, SelectVecTy)); + } + Select->replaceAllUsesWith( + createPseudoInstCall(M, Builder, VecWideCondBitsel, SelectVecTy, + {Cmp, SelectOp0, SelectOp1})); + + return true; +} + +// Convert +// +// %2 =3D icmp [sgt|ugt|slt|ult] %0, %1 +// %5 =3D select %2, %3, %4 +// +// to +// +// 5 =3D call @Movcond.[cond].*(%1, %0, %3, %4) +// +// to more closely match TCG semantics. +static bool convertSelectICmpToMovcond(Module &M, SelectInst *Select, + ICmpInst *ICmp, + ICmpInst::Predicate &Pred, + Value *ICmpOp0, Value *ICmpOp1, + Value *SelectOp0, Value *SelectOp1)= { + // We only handle integers, we have no movcond equivalent in gvec + auto *IntTy =3D dyn_cast(Select->getType()); + if (!IntTy) { + return false; + } + + // If the type of the comparison does not match the return type of the + // select statement, we cannot do anything so skip + if (ICmpOp0->getType() !=3D IntTy) { + return false; + } + + IRBuilder<> Builder(Select); + if (cast(ICmpOp0->getType())->getBitWidth() < + IntTy->getBitWidth()) { + if (ICmp->isSigned(Pred)) { + ICmpOp0 =3D Builder.CreateSExt(ICmpOp0, IntTy); + ICmpOp1 =3D Builder.CreateSExt(ICmpOp1, IntTy); + } else { + ICmpOp0 =3D Builder.CreateZExt(ICmpOp0, IntTy); + ICmpOp1 =3D Builder.CreateZExt(ICmpOp1, IntTy); + } + } + + // Create @Movcond.[slt|...].* function + Select->replaceAllUsesWith( + createPseudoInstCall(M, Builder, Movcond, IntTy, + {ConstantInt::get(IntTy, Pred), ICmpOp0, ICmp= Op1, + SelectOp0, SelectOp1})); + + return true; +} + +// Specialize +// +// %2 =3D icmp [sgt|ugt|slt|ult] %0, %1 +// %5 =3D select %2, %3, %4 +// +// to either maximum/minimum, vector operations matching TCG, or a conditi= onal +// move that also matches TCG in sematics. +static void convertSelectICmp(Module &M, SelectInst *Select, ICmpInst *ICm= p) { + // Given + // %2 =3D icmp [sgt|ugt|slt|ult] %0, %1 + // %5 =3D select %2, %3, %4 + assert(Select->getCondition() =3D=3D ICmp); + Value *ICmpOp0 =3D ICmp->getOperand(0); + Value *ICmpOp1 =3D ICmp->getOperand(1); + Value *SelectOp0 =3D Select->getTrueValue(); + Value *SelectOp1 =3D Select->getFalseValue(); + ICmpInst::Predicate Pred =3D ICmp->getPredicate(); + + // First try to convert to min/max + // %5 =3D [s|u][max|min] %0, %1 + if (convertSelectICmpToMinMax(M, Select, ICmp, Pred, ICmpOp0, ICmpOp1, + SelectOp0, SelectOp1)) { + return; + } + + // Secondly try convert icmp -> @VecCompare, select -> @VecWideCondBit= sel + if (convertSelectICmpToVecBitsel(M, Select, ICmp, Pred, ICmpOp0, ICmpO= p1, + SelectOp0, SelectOp1)) { + return; + } + + // If min/max and vector conversion failed we fallback to a movcond + // %5 =3D call @Movcond.[cond].*(%1, %0, %3, %4) + convertSelectICmpToMovcond(M, Select, ICmp, Pred, ICmpOp0, ICmpOp1, + SelectOp0, SelectOp1); +} + +// Convert QEMU guest loads/stores represented by calls such as +// +// call cpu_ldsw_be*(), +// call cpu_stq_le*(), +// +// and friends, to pseudo instructions +// +// %5 =3D call @GuestLoad.*(%addr, %sign, %size, %endian); +// %5 =3D call @GuestStore.*(%addr, %value, %size, %endian); +// +// Makes the backend agnostic to what instructions or calls are used to +// represent loads and stores. +static void convertQemuLoadStoreToPseudoInst(Module &M, CallInst *Call, + EraseInstVec &InstToErase, + UsageCountMap &UsageMap) { + Function *F =3D Call->getCalledFunction(); + StringRef Name =3D F->getName(); + if (Name.consume_front("cpu_")) { + bool IsLoad =3D Name.consume_front("ld"); + bool IsStore =3D !IsLoad and Name.consume_front("st"); + if (IsLoad or IsStore) { + bool Signed =3D !Name.consume_front("u"); + + uint8_t Size =3D 0; + switch (Name[0]) { + case 'b': + Size =3D 1; + break; + case 'w': + Size =3D 2; + break; + case 'l': + Size =3D 4; + break; + case 'q': + Size =3D 8; + break; + default: + abort(); + } + + uint8_t Endianness =3D 0; + if (Size > 1 and Size < 8) { + Name =3D Name.drop_front(2); + switch (Name[0]) { + case 'l': + Endianness =3D 1; + break; + case 'b': + Endianness =3D 2; + break; + default: + // TODO: we need to parse the `MemOpIndex` in the seco= nd to + // last argument, for now just assume little endian, s= ame + // goes for signedness. + Endianness =3D 1; + } + } + + IRBuilder<> Builder(Call); + Value *AddrOp =3D Call->getArgOperand(1); + IntegerType *FlagTy =3D Builder.getInt8Ty(); + Value *SizeOp =3D ConstantInt::get(FlagTy, Size); + Value *EndianOp =3D ConstantInt::get(FlagTy, Endianness); + CallInst *NewCall; + if (IsLoad) { + Value *SignOp =3D ConstantInt::get(FlagTy, Signed); + IntegerType *RetTy =3D cast(Call->getType()); + NewCall =3D + createPseudoInstCall(M, Builder, GuestLoad, RetTy, + {AddrOp, SignOp, SizeOp, EndianOp= }); + } else { + Value *ValueOp =3D Call->getArgOperand(2); + NewCall =3D createPseudoInstCall( + M, Builder, GuestStore, Builder.getVoidTy(), + {AddrOp, ValueOp, SizeOp, EndianOp}); + } + Call->replaceAllUsesWith(NewCall); + InstToErase.push_back(Call); + } + } +} + +// Convert QEMU exception calls +// +// call raise_exception_ra(...), +// ... +// +// to a pseudo instruction +// +// %5 =3D call @Exception.*(...); +// +// Makes the backend agnostic to what instructions or calls are used to +// represent exceptions, and the list of sources can be expanded here. +static void convertExceptionCallsToPseudoInst(Module &M, CallInst *Call) { + Function *F =3D Call->getCalledFunction(); + if (F->getName() =3D=3D "raise_exception_ra") { + IRBuilder<> Builder(Call); + Value *Op0 =3D Call->getArgOperand(0); + Value *Op1 =3D Call->getArgOperand(1); + Call->replaceAllUsesWith(createPseudoInstCall( + M, Builder, Exception, Builder.getVoidTy(), {Op0, Op1})); + } +} + +// Convert QEMU exception calls +// +// %0 =3D call @llvm.returnaddr(...), +// %1 =3D ptrtoint %0 +// ... +// +// to a pseudo instruction +// +// %0 =3D call @getpc(...); +// +static void convertReturnAddrToPseudoInst(Module &M, CallInst *Call) { + Function *F =3D Call->getCalledFunction(); + if (!F->isIntrinsic() or F->getIntrinsicID() !=3D Intrinsic::returnadd= ress) { + return; + } + if (!Call->hasOneUse()) { + return; + } + + auto *PtrToInt =3D dyn_cast(*Call->user_begin()); + if (!PtrToInt) { + return; + } + + IRBuilder<> Builder(PtrToInt); + PtrToInt->replaceAllUsesWith( + createPseudoInstCall(M, Builder, GetPC, PtrToInt->getType(), {})); +} + +// Convert QEMU exception calls +// +// %0 =3D call @llvm.returnaddr(...), +// %1 =3D ptrtoint %0 +// ... +// +// to a pseudo instruction +// +// %0 =3D call @getpc(...); +// +static void convertImmediateSelectAccessGlobal(EraseInstVec &InstToErase, + Module &M, CallInst *Call) { + PseudoInst PI =3D getPseudoInstFromCall(Call); + if (PI !=3D AccessGlobalArray) { + return; + } + + if (!Call->hasOneUser()) { + return; + } + + auto *Load =3D dyn_cast(*Call->user_begin()); + if (!Load) { + return; + } + + auto *Zext =3D dyn_cast(Call->getArgOperand(1)); + if (!Zext) { + return; + } + + auto *Select =3D dyn_cast(Zext->getOperand(0)); + if (!Select) { + return; + } + + if (!Zext->hasOneUse() or !Select->hasOneUse()) { + return; + } + + Value *Cond =3D Select->getCondition(); + Value *Arg1 =3D Select->getTrueValue(); + Value *Arg2 =3D Select->getFalseValue(); + + if (!isa(Arg1) or !isa(Arg2)) { + return; + } + + IRBuilder<> Builder(Select); + Function *AccessGlobalFn =3D Call->getCalledFunction(); + Value *TypeIndex =3D Call->getArgOperand(0); + Value *Offset =3D Call->getArgOperand(1); + Value *Arg1Zext =3D Builder.CreateZExt(Arg1, Zext->getType()); + Value *Arg2Zext =3D Builder.CreateZExt(Arg2, Zext->getType()); + CallInst *Access1 =3D + Builder.CreateCall(AccessGlobalFn, {TypeIndex, Offset, Arg1Zext}); + CallInst *Access2 =3D + Builder.CreateCall(AccessGlobalFn, {TypeIndex, Offset, Arg2Zext}); + LoadInst *Load1 =3D Builder.CreateLoad(Load->getType(), Access1); + LoadInst *Load2 =3D Builder.CreateLoad(Load->getType(), Access2); + Value *NewSelect =3D Builder.CreateSelect(Cond, Load1, Load2); + + InstToErase.push_back(Load); + InstToErase.push_back(Call); + + Load->replaceAllUsesWith(NewSelect); +} + +struct DeclReplaceInfo { + bool Valid =3D false; + Value *Zext =3D nullptr; + Value *Select =3D nullptr; + Value *Cond =3D nullptr; + Value *Arg1 =3D nullptr; + Value *Arg2 =3D nullptr; +}; + +static DeclReplaceInfo isReplaceableDeclCall(Value *A) { + auto *Zext =3D dyn_cast(A); + if (!Zext) { + return {}; + } + + auto *Select =3D dyn_cast(Zext->getOperand(0)); + if (!Select) { + return {}; + } + + if (!Zext->hasOneUse() or !Select->hasOneUse()) { + return {}; + } + + Value *Cond =3D Select->getCondition(); + Value *Arg1 =3D Select->getTrueValue(); + Value *Arg2 =3D Select->getFalseValue(); + + if (!isa(Arg1) or !isa(Arg2)) { + return {}; + } + + return {true, Zext, Select, Cond, Arg1, Arg2}; +} + +static void convertImmediateDeclCall(EraseInstVec &InstToErase, Module &M, + CallInst *Call) { + if (!Call->getCalledFunction()->isDeclaration()) { + return; + } + + if (!Call->hasOneUser()) { + return; + } + + SmallVector Args1; + SmallVector Args2; + DeclReplaceInfo Info{}; + IRBuilder<> Builder(Call); + for (auto &A : Call->args()) { + if (!Info.Valid) { + Info =3D isReplaceableDeclCall(A); + if (Info.Valid) { + Value *Arg1Zext =3D + Builder.CreateZExt(Info.Arg1, Info.Zext->getType()); + Value *Arg2Zext =3D + Builder.CreateZExt(Info.Arg2, Info.Zext->getType()); + Args1.push_back(Arg1Zext); + Args2.push_back(Arg2Zext); + continue; + } + } + + Args1.push_back(A); + Args2.push_back(A); + } + + if (!Info.Valid) { + return; + } + + Function *F =3D Call->getCalledFunction(); + CallInst *Access1 =3D Builder.CreateCall(F, Args1); + CallInst *Access2 =3D Builder.CreateCall(F, Args2); + Value *NewSelect =3D Builder.CreateSelect(Info.Cond, Access1, Access2); + Access1->setDebugLoc(Call->getDebugLoc()); + Access2->setDebugLoc(Call->getDebugLoc()); + + // InstToErase.push_back(Load); + InstToErase.push_back(Call); + InstToErase.push_back(cast(Info.Zext)); + + Call->replaceAllUsesWith(NewSelect); +} + +static void convertUserBranchInstructions(Module &M, + DominatorTreeAnalysis::Result &D= T, + const ExitSet &Exits, + CallInst *Call) { + Function *F =3D Call->getCalledFunction(); + if (F->getName() !=3D UserPCRelBranchFunc) { + return; + } + + // Make sure the user-supplied functions exist and have the correct + // signature. + Function *BranchF =3D M.getFunction(UserPCRelBranchFunc); + Function *CondF =3D M.getFunction(UserPCRelBranchConditionalFunc); + Function *FallF =3D M.getFunction(UserPCRelBranchFallthroughFunc); + if (!CondF or !FallF or BranchF->getType() !=3D CondF->getType() or + FallF->getType()->getFunctionNumParams()) { + return; + } + + BasicBlock *BB =3D Call->getParent(); + bool DominatesAllExits =3D true; + for (BasicBlock *E : Exits) { + if (!DT.dominates(BB, E)) { + DominatesAllExits =3D false; + } + } + // If the call to the user-supplied pc-relative jump function dominate= s all + // exit blocks, then leave it be, it's a single relative jump with one= exit. + if (DominatesAllExits) { + return; + } + + // Otherwise add a fallthrough operation to each exit block. + for (BasicBlock *E : Exits) { + IRBuilder<> Builder(E->getTerminator()); + Builder.CreateCall(FallF, {}); + } + + // And replace the current jump operation with a "conditinal" one, so + // QEMU knows how to chain the generated code. + Call->setCalledFunction(CondF); +} + +// +// Following functions help with converting between different types of +// instructions to pseudo instructions, particularly ones that write +// to a pointer, aka the Vec*Store pseudo instructions +// + +static PseudoInst instructionToStorePseudoInst(unsigned Opcode) { + switch (Opcode) { + case Instruction::Trunc: + return VecTruncStore; + case Instruction::ZExt: + return VecZExtStore; + case Instruction::SExt: + return VecSExtStore; + case Instruction::Select: + return VecSelectStore; + case Instruction::Add: + return VecAddStore; + case Instruction::Sub: + return VecSubStore; + case Instruction::Mul: + return VecMulStore; + case Instruction::Xor: + return VecXorStore; + case Instruction::Or: + return VecOrStore; + case Instruction::And: + return VecAndStore; + case Instruction::Shl: + return VecShlStore; + case Instruction::LShr: + return VecLShrStore; + case Instruction::AShr: + return VecAShrStore; + default: + abort(); + } +} + +static PseudoInst pseudoInstToStorePseudoInst(PseudoInst Inst) { + switch (Inst) { + case VecNot: + return VecNotStore; + case VecAddScalar: + return VecAddScalarStore; + case VecSubScalar: + return VecSubScalarStore; + case VecMulScalar: + return VecMulScalarStore; + case VecXorScalar: + return VecXorScalarStore; + case VecOrScalar: + return VecOrScalarStore; + case VecAndScalar: + return VecAndScalarStore; + case VecShlScalar: + return VecShlScalarStore; + case VecLShrScalar: + return VecLShrScalarStore; + case VecAShrScalar: + return VecAShrScalarStore; + case VecWideCondBitsel: + return VecWideCondBitselStore; + default: + abort(); + } +} + +static PseudoInst intrinsicToStorePseudoInst(unsigned IntrinsicID) { + switch (IntrinsicID) { + case Intrinsic::sadd_sat: + return VecSignedSatAddStore; + case Intrinsic::ssub_sat: + return VecSignedSatSubStore; + case Intrinsic::fshr: + return VecFunnelShrStore; + case Intrinsic::abs: + return VecAbsStore; + case Intrinsic::smax: + return VecSignedMaxStore; + case Intrinsic::umax: + return VecUnsignedMaxStore; + case Intrinsic::smin: + return VecSignedMinStore; + case Intrinsic::umin: + return VecUnsignedMinStore; + case Intrinsic::ctlz: + return VecCtlzStore; + case Intrinsic::cttz: + return VecCttzStore; + case Intrinsic::ctpop: + return VecCtpopStore; + default: + abort(); + } +} + +// For binary/unary ops on vectors where the result is stored to a +// pointer +// +// %3 =3D %1 [op] %2 +// %4 =3D bitcast i8* %0 to * +// store %3, * %4 +// +// to +// +// call @Vec[Op]Store.*(%0, %1, %2) +// +// This deals with the duality of pointers and vectors, and +// simplifies the backend. We previously kept a map on the +// side to propagate "vector"-ness from %3 to %4 via the store, +// no longer! +static void convertVecStoreToPseudoInst(EraseInstVec &InstToErase, Module = &M, + StoreInst *Store) { + Value *ValueOp =3D Store->getValueOperand(); + Type *ValueTy =3D ValueOp->getType(); + if (!ValueTy->isVectorTy()) { + return; + } + + // Ensure store and binary op. are in the same basic + // block since the op. is moved to the store. + bool InSameBB =3D + cast(ValueOp)->getParent() =3D=3D Store->getParent(); + if (!InSameBB) { + return; + } + + SmallVector Args; + Value *PtrOp =3D Store->getPointerOperand(); + if (auto *BinOp =3D dyn_cast(ValueOp)) { + Instruction *Inst =3D cast(ValueOp); + PseudoInst NewInst =3D instructionToStorePseudoInst(BinOp->getOpco= de()); + IRBuilder<> Builder(Store); + // Add one to account for extra store pointer + // argument of Vec*Store pseudo instructions. + const uint8_t SharedArgCount =3D pseudoInstArgCount(NewInst) - 1; + Args.push_back(PtrOp); + for (unsigned I =3D 0; I < SharedArgCount; ++I) { + Value *Op =3D Inst->getOperand(I); + Args.push_back(Op); + } + createPseudoInstCall(M, Builder, NewInst, Builder.getVoidTy(), Arg= s); + } else if (auto *Call =3D dyn_cast(ValueOp)) { + Function *F =3D Call->getCalledFunction(); + PseudoInst OldInst =3D getPseudoInstFromCall(Call); + if (OldInst !=3D InvalidPseudoInst) { + // Map scalar vector pseudo instructions to + // store variants + PseudoInst NewInst =3D pseudoInstToStorePseudoInst(OldInst); + IRBuilder<> Builder(Store); + Args.push_back(PtrOp); + for (Value *Op : Call->args()) { + Args.push_back(Op); + } + createPseudoInstCall(M, Builder, NewInst, Builder.getVoidTy(), + Args); + } else if (F->isIntrinsic()) { + Instruction *Inst =3D cast(ValueOp); + PseudoInst NewInst =3D + intrinsicToStorePseudoInst(F->getIntrinsicID()); + // Add one to account for extra store pointer + // argument of Vec*Store pseudo instructions. + const uint8_t SharedArgCount =3D pseudoInstArgCount(NewInst) -= 1; + IRBuilder<> Builder(Store); + Args.push_back(PtrOp); + for (unsigned I =3D 0; I < SharedArgCount; ++I) { + Args.push_back(Inst->getOperand(I)); + } + createPseudoInstCall(M, Builder, NewInst, Builder.getVoidTy(), + Args); + } + } else if (auto *Load =3D dyn_cast(ValueOp)) { + auto *VecTy =3D cast(Load->getType()); + auto *IntTy =3D cast(VecTy->getElementType()); + uint32_t LlvmSize =3D IntTy->getBitWidth(); + uint32_t VectorElements =3D compat::getVectorElementCount(VecTy); + IRBuilder<> Builder(Store); + auto *Size =3D Builder.getInt64(LlvmSize * VectorElements); + Builder.CreateMemCpy(Store->getPointerOperand(), + Store->getPointerAlignment(M.getDataLayout()), + Load->getPointerOperand(), + Load->getPointerAlignment(M.getDataLayout()), + Size); + // Remove load if possible, won't get cleaned up by DCE + if (Load->hasOneUse()) { + InstToErase.push_back(cast(Load)); + } + } else { + Instruction *Inst =3D cast(ValueOp); + + PseudoInst NewInst =3D instructionToStorePseudoInst(Inst->getOpcod= e()); + // Add one to account for extra store pointer + // argument of Vec*Store pseudo instructions. + const uint8_t SharedArgCount =3D pseudoInstArgCount(NewInst) - 2; + + assert(SharedArgCount > 0 and + SharedArgCount <=3D (uint8_t)Inst->getNumOperands()); + IRBuilder<> Builder(Store); + SmallVector Args; + auto SizeTy =3D Type::getInt8Ty(M.getContext()); + Args.push_back(ConstantInt::get( + SizeTy, + cast(ValueTy)->getElementType()->getIntegerBitWidt= h())); + Args.push_back(PtrOp); + for (uint8_t I =3D 0; I < SharedArgCount; ++I) { + Args.push_back(Inst->getOperand(I)); + } + createPseudoInstCall(M, Builder, NewInst, Builder.getVoidTy(), Arg= s); + } + + // Remove store instruction, this ensures DCE + // can cleanup the rest, we also remove ValueOp + // here since it's a call and won't get cleaned + // by DCE. + if (!isa(ValueOp)) { + InstToErase.push_back(cast(ValueOp)); + } + InstToErase.push_back(Store); +} diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/CanonicalizeIR= .hpp b/subprojects/helper-to-tcg/src/PrepareForTcgPass/CanonicalizeIR.hpp new file mode 100644 index 0000000000..089cd75a7b --- /dev/null +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/CanonicalizeIR.hpp @@ -0,0 +1,24 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include + +struct VectorLayout; + +void canonicalizeIR(llvm::Module &M, llvm::ModuleAnalysisManager &MAM, con= st VectorLayout &VL); diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass= .cpp index 10129fa245..71749e2f6f 100644 --- a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp @@ -16,6 +16,7 @@ // =20 #include "PrepareForTcgPass.hpp" +#include "CanonicalizeIR.hpp" #include "CmdLineOptions.hpp" #include "TransformGEPs.hpp" =20 @@ -140,5 +141,6 @@ PreservedAnalyses PrepareForTcgPass::run(Module &M, for (Function &F : M) { transformGEPs(M, F, ResultTcgGlobalMap, TypeIndexMap, DebugInfo); } + canonicalizeIR(M, MAM, VL); return PreservedAnalyses::none(); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380986; cv=none; d=zohomail.com; s=zohoarc; b=Kz9beERjMXzNPwHFH3UBmgL8bi8cS1Y5A/VwVKIdBCxtGY6qpTj1aPaU5L1H1Cp9NDKq2XSuIOx/1CvLB2V2vDomJi8JCC7oVuUU8BtbaATK0dAGPw+MUlGo4NHOneehGh75cMY3iMYzr1Gj2J1kyHBfMb4aWFAj9MKgjTdRmDQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380986; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=HnCTtpuYw/p0eFuGQNJjUUucCE/tt34zGt60GfprXAY=; b=iwXaU2KcbG2en0IOOl5UAvRihUiYZJJU44aNruNj3jY5yxInFmIVwXJsGG8ca8m4MB2zYF799KNpYtuLL8FEWWW3xd/i1BZRnN2RqGyb7uNT+Scb3PTjKDXkk8UEZelaWhfmKMDbA06Muye0q2zgTvJGWSYUNhz9APCrlRDGhBU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380986513392.2863458729572; Wed, 29 Jul 2026 20:09:46 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH70-00049B-FY; Wed, 29 Jul 2026 23:07:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6r-0003yv-Dj for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:01 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6o-0002xK-Hz for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=HnCTtpuYw/p0eFuGQNJjUUucCE/tt34zGt60GfprXAY=; b=WWgc7iaoB4AC1HS ygbk4BuX+dtDjRW5vCx0eu+qvGLedUmxoXvzDkJoV7huHjk+WuX5NRhVvhz49p21gzIUx80wXB9Us A+RsFvXzzuJUj9kSzcDIZR3VstZNBQL7PXvRtClWlNXO/SZItX7lyYaBcGS2lAsf/JLqDWdcFmUQj Uc=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 28/50] helper-to-tcg: PrepareForTcgPass, identity map trivial expressions Date: Thu, 30 Jul 2026 05:10:02 +0200 Message-ID: <20260730031025.12926-29-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380987619158500 Content-Type: text/plain; charset="utf-8" Transformation of the IR, identity mapping expressions which would amount to nothing more than a move when emitted as TCG, but is required in LLVM IR to not break the IR. Trivial expressions are mapped to a `@IdentityMap` pseudo instruction allowing them to be dealt with in a uniform manner down the line. Signed-off-by: Anton Johansson --- subprojects/helper-to-tcg/meson.build | 1 + .../src/PrepareForTcgPass/IdentityMap.cpp | 91 +++++++++++++++++++ .../src/PrepareForTcgPass/IdentityMap.hpp | 39 ++++++++ .../PrepareForTcgPass/PrepareForTcgPass.cpp | 4 + 4 files changed, 135 insertions(+) create mode 100644 subprojects/helper-to-tcg/src/PrepareForTcgPass/Identit= yMap.cpp create mode 100644 subprojects/helper-to-tcg/src/PrepareForTcgPass/Identit= yMap.hpp diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 79ce0c6dd8..c88c759ba6 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -47,6 +47,7 @@ sources =3D [ 'src/PrepareForTcgPass/PrepareForTcgPass.cpp', 'src/PrepareForTcgPass/TransformGEPs.cpp', 'src/PrepareForTcgPass/CanonicalizeIR.cpp', + 'src/PrepareForTcgPass/IdentityMap.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/IdentityMap.cp= p b/subprojects/helper-to-tcg/src/PrepareForTcgPass/IdentityMap.cpp new file mode 100644 index 0000000000..b9f4c8330f --- /dev/null +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/IdentityMap.cpp @@ -0,0 +1,91 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "IdentityMap.hpp" +#include "PseudoInst.hpp" +#include "TcgType.hpp" + +#include +#include +#include +#include +#include + +using namespace llvm; + +void identityMap(Module &M, Function &F) { + SmallVector InstToErase; + + for (Instruction &I : instructions(F)) { + auto *ZExt =3D dyn_cast(&I); + if (ZExt) { + auto *SrcIntTy =3D + dyn_cast(ZExt->getOperand(0)->getType()); + auto *DstIntTy =3D dyn_cast(ZExt->getType()); + if (!SrcIntTy or !DstIntTy) { + continue; + } + + auto SrcSize =3D ValueSize::fromLlvmType(SrcIntTy); + auto DstSize =3D ValueSize::fromLlvmType(DstIntTy); + if (!SrcSize or !DstSize) { + continue; + } + + // TODO: Hack again to get bit width from icmp arguments, shou= ld + // widen in canonicalization phase. + if (SrcSize->LlvmBitWidth =3D=3D 1) { + auto *ICmp =3D dyn_cast(ZExt->getOperand(0)); + if (ICmp) { + auto *ICmpOp =3D ICmp->getOperand(0); + auto OpSize =3D ValueSize::fromLlvmType( + cast(ICmpOp->getType())); + if (!OpSize) { + continue; + } + SrcSize =3D *OpSize; + } + } + + // Only identity map when TCG sizes match. + if (SrcSize->TcgBitWidth !=3D DstSize->TcgBitWidth) { + continue; + } + + IRBuilder<> Builder(&I); + ZExt->replaceAllUsesWith(createPseudoInstCall( + M, Builder, IdentityMap, DstIntTy, {ZExt->getOperand(0)})); + InstToErase.push_back(&I); + } else if (auto *Load =3D dyn_cast(&I); + Load and Load->getType()->isVectorTy()) { + Value *Ptr =3D Load->getPointerOperand(); + IRBuilder<> Builder(&I); + Load->replaceAllUsesWith(createPseudoInstCall( + M, Builder, IdentityMap, Load->getType(), {Ptr})); + InstToErase.push_back(&I); + } else if (isa(&I)) { + IRBuilder<> Builder(&I); + I.replaceAllUsesWith(createPseudoInstCall( + M, Builder, IdentityMap, I.getType(), {I.getOperand(0)})); + InstToErase.push_back(&I); + } + } + + for (Instruction *I : InstToErase) { + I->eraseFromParent(); + } +} diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/IdentityMap.hp= p b/subprojects/helper-to-tcg/src/PrepareForTcgPass/IdentityMap.hpp new file mode 100644 index 0000000000..25de0a2c71 --- /dev/null +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/IdentityMap.hpp @@ -0,0 +1,39 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include +#include + +// +// Transformation of the IR, taking what would become trivial unary operat= ions +// and maps them to a single @IdentityMap pseudo instruction. +// +// To motivate further, in order to produce nice IR on the other end, gene= rally +// the operands of these trivial expressions needs to be forwarded and tre= ated +// as the destination value (identity mapped). However, directly removing= these +// instructions will result in broken LLVM IR (consider zext i8, i32 where= both +// the source and destination would map to TCGv_i32). +// +// Moreover, handling these identity mapped values in an adhoc way quickly +// becomes cumbersome and spreads throughout the codebase. Therefore, +// introducing @IdentityMap allows code further down the pipeline to ignor= e the +// source of the identity map. +// + +void identityMap(llvm::Module &M, llvm::Function &F); diff --git a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgP= ass.cpp b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass= .cpp index 71749e2f6f..4185af7956 100644 --- a/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp +++ b/subprojects/helper-to-tcg/src/PrepareForTcgPass/PrepareForTcgPass.cpp @@ -18,6 +18,7 @@ #include "PrepareForTcgPass.hpp" #include "CanonicalizeIR.hpp" #include "CmdLineOptions.hpp" +#include "IdentityMap.hpp" #include "TransformGEPs.hpp" =20 #include @@ -142,5 +143,8 @@ PreservedAnalyses PrepareForTcgPass::run(Module &M, transformGEPs(M, F, ResultTcgGlobalMap, TypeIndexMap, DebugInfo); } canonicalizeIR(M, MAM, VL); + for (Function &F : M) { + identityMap(M, F); + } return PreservedAnalyses::none(); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380884; cv=none; d=zohomail.com; s=zohoarc; b=dH9IiuSLGkkaIwWOwxDL99qjs4I2lcYX5fqErO6nNC9E8VYOMpU5HikaMeTdD4kYmOwvLn3s7s0X96sa1Lb9I2GnEisyHbfUpjbzeWSzLOzozJ+H0gsLB3oS1ZTBnjeNy766xdnxa0B+O5UIbtbW+vQNk9T7tTXIMNyB+wCQ2JE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380884; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=BpKyJdGN9i5for/iI7NHXUTpC+D8XweQHkAEvI9NdOM=; b=Na/G6MbY1Rd8Qi8XsDFEZUVwAt+fp7dICRGvZHExT2fNBK8H6v/iPPUOUMEO8RzSfLkIBnBc/nZ4TkrkULRILoRHGQFRk0dcaxPVWsnfvSBEG7qcku2B6l1laJU98NwMtFo7irPqxr56zgtkR9PjWkHQmQKPhcoxLnRqza6qeu0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380884168370.6954923013345; Wed, 29 Jul 2026 20:08:04 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7B-0004Vk-PT; Wed, 29 Jul 2026 23:07:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH72-0004FX-Fn for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:12 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6q-0002xd-G9 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=BpKyJdGN9i5for/iI7NHXUTpC+D8XweQHkAEvI9NdOM=; b=nqDlHokHNfrGhLn MPhJQaZZvnE0/H7g1nPX0rV2LxHZx8a7/ao/PVjzMDOIHlHFB4jNrt8tSiwSxOWqs9F8XDsGuUYri PXLBTxr5BL3nIMz0v1aaEwM2H5ecm1CpphS2LCeS8tqLf8SGm0rsPfnTfXYtOeaWN7IdyHj7+qRDV sg=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 29/50] helper-to-tcg: Introduce TcgV structure Date: Thu, 30 Jul 2026 05:10:03 +0200 Message-ID: <20260730031025.12926-30-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380885330158500 Content-Type: text/plain; charset="utf-8" Adds a struct representing everything a LLVM value might map to in TCG, this includes: * TCGv_i* (IrValue); * TCGv_ptr (IrPtr); * TCGLabel (IrLabel); * 123123ull (IrImmediate); * intptr_t (IrPtrToOffset). Every `TcgV` value is assigned an increasing identifier, a kind (list above), a size, and optinally a name along with some extra flags. Two values are considered equal if their identifiers are equal. For instance, this can mean one identifier might describe different LLVM sizes at different points in a function, which is very useful when mapping semantics from LLVM IR to TCG. Signed-off-by: Anton Johansson --- subprojects/helper-to-tcg/include/TcgType.hpp | 276 ++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 subprojects/helper-to-tcg/include/TcgType.hpp diff --git a/subprojects/helper-to-tcg/include/TcgType.hpp b/subprojects/he= lper-to-tcg/include/TcgType.hpp new file mode 100644 index 0000000000..8cc46a6b1f --- /dev/null +++ b/subprojects/helper-to-tcg/include/TcgType.hpp @@ -0,0 +1,276 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include "Error.hpp" +#include "LlvmCompat.hpp" + +#include +#include +#include +#include + +#include +#include +#include +#include // std::pair + +// Data representing allowed vector and value sizes. + +// Sizes corresponding to a TCGv_i* register. +enum AllowedTcgSize : uint8_t { + T32 =3D 32, + T64 =3D 64, + T128 =3D 128, +}; + +// Sizes corresponding of allowed LLVM values, operations smaller than +// `AllowedTcgSize` act on these sizes. +enum AllowedLlvmSize : uint8_t { + I1 =3D 1, + I8 =3D 8, + I16 =3D 16, + I32 =3D 32, + I64 =3D 64, +}; + +// Despite limiting sizes to an enum, when assigned from runtime values th= ey may +// still differ. +inline bool verifyLlvmSize(AllowedLlvmSize S) { + switch (S) { + case I1: + case I8: + case I16: + case I32: + case I64: + return true; + default: + return false; + }; +} + +// Size of an integer value, combining a TCG and LLVM size. +struct ValueSize { + AllowedTcgSize TcgBitWidth; + AllowedLlvmSize LlvmBitWidth; + + static llvm::Expected fromBitWidth(size_t BitWidth) { + ValueSize Ret; + if (BitWidth <=3D 32) { + Ret.TcgBitWidth =3D T32; + } else if (BitWidth <=3D 64) { + Ret.TcgBitWidth =3D T64; + } else { + Ret.TcgBitWidth =3D T128; + } + Ret.LlvmBitWidth =3D (AllowedLlvmSize)BitWidth; + // There's no runtime sanity checks that an enum is not just any i= nteger + // value, so verify manually. + if (verifyLlvmSize(Ret.LlvmBitWidth)) { + return Ret; + } else { + return mkError("Invalid bit width"); + } + } + + static llvm::Expected fromLlvmType(llvm::IntegerType *Ty) { + return fromBitWidth(Ty->getBitWidth()); + } +}; + +struct VectorSize { + uint8_t ElementCount; + AllowedLlvmSize ElementBitWidth; + + inline size_t bytes() const { return (ElementCount * ElementBitWidth) = / 8; } + + static llvm::Expected fromLlvmType(llvm::VectorType *Ty) { + auto *IntTy =3D llvm::dyn_cast(Ty->getElementTy= pe()); + if (!IntTy) { + return mkError( + "Vectors of non-integer element type not supported!\n"); + } + VectorSize Ret{ + (uint8_t)compat::getVectorElementCount(Ty), + (AllowedLlvmSize)IntTy->getBitWidth(), + }; + // There's no runtime sanity checks that an enum is not just any i= nteger + // value, so verify manually. + if (verifyLlvmSize(Ret.ElementBitWidth)) { + return Ret; + } else { + return mkError("Invalid bit width"); + } + } +}; + +union TcgSize { + VectorSize Vec; + ValueSize Val; +}; + +// clang-format off +enum TcgKind : uint8_t { + IrInvalid =3D 0, + IrValue =3D 1, // TCG register value (TCGv_i*) + IrImmediate =3D 2, // Immediate argument to TCG operation ([u]int*_= t) + IrPtr =3D 4, // TCG host pointer (TCGv_ptr) + IrPtrToOffset =3D 8, // Target "gvec" vector (intptr_t) + IrLabel =3D 16, // TCG label (TCGv_label) +}; +// clang-format on + +// Describes a single value to be output in TCG, discriminated by `TcgKind= `. +// +// This data is designed to be copied around and each value is identified = via a +// unique `Id`, as a result the "same" `TcgV` can take on e.g. different s= izes +// at different points in function, which allows one TCG variable to repre= sent +// multiple smaller "logical" LLVM sizes. +// +// TODO: +// +// * There is overlap between `Kind =3D=3D IrImmediate` and `(ConstantEx= pression +// and Kind =3D=3D IrValue)` that is not obvious, the condition `!Name= .empty()` +// is also rather similar to `ConstantExpression` in a lot of cases. +// +// * `Name` should not be string, this is resulting in redundant copies = and is +// also completely unnecessary given our usage pattern. `Name` is nev= er +// modified, and all strings are created by the same few passes. A be= tter +// solution would be to use a `StringSaver/BumpAllocator` in `CEmitter= ` and +// use `StringRef`s everywhere else. +// +struct TcgV { + uint16_t Id =3D 0; + TcgKind Kind =3D IrInvalid; + TcgSize Size; + bool ConstantExpression =3D false; + std::string Name =3D ""; + + // Static id used to identify `TcgV`s + inline static uint16_t IdCounter =3D 0; + static void resetId() { IdCounter =3D 0; } + static uint16_t getId() { return IdCounter++; } + + // Helper functions for accessing size fields. + inline ValueSize intSize() const { + assert(Kind =3D=3D IrImmediate or Kind =3D=3D IrValue); + return Size.Val; + } + + inline VectorSize vecSize() const { + assert(Kind =3D=3D IrPtrToOffset); + return Size.Vec; + } + + // Return as `int` to reduce casts when printing and to ease compariso= ns. + inline int tcgBitWidth() const { return intSize().TcgBitWidth; } + inline int llvmBitWidth() const { return intSize().LlvmBitWidth; } + + static TcgV makeVector(VectorSize Size) { + return TcgV({}, {.Vec =3D Size}, IrPtrToOffset); + } + + static TcgV makeImmediate(llvm::StringRef Name, ValueSize Size) { + return TcgV(Name.str(), {.Val =3D Size}, IrImmediate); + } + + static TcgV makeTemp(ValueSize Size, TcgKind Kind) { + return TcgV({}, {.Val =3D Size}, Kind); + } + + static TcgV makeConstantExpression(llvm::StringRef Expression, + ValueSize Size, TcgKind Kind) { + TcgV Tcg(Expression.str(), {.Val =3D Size}, Kind); + Tcg.ConstantExpression =3D true; + return Tcg; + } + + static TcgV makeLabel() { return TcgV("", {.Val =3D {T32, I32}}, IrLab= el); } + + TcgV() =3D default; + + TcgV(std::string Name, TcgSize Size, TcgKind Kind) + : Id(getId()), Kind(Kind), Size(Size), Name(Name) {} + + // Equality between two values it determined only by the assigned id, + // consider a 16- to 8-bit truncation: + // + // %1 =3D trunc i8, i16 %0, + // + // which after identity mapping becomes + // + // %1 =3D call i8 @IdentityMap.i16.i8(i16 %0). + // + // Identity mapping will copy the `TcgV` assigned to `%0` to `%1`, but= `%1` + // will retain its `LlvmSize` needed to emit correctly sized operation= s down + // the line. Despite differing in `LlvmSize` both `%0` and `%1` will = be + // emitted as the same TCG value with type `TCGv_i32`. + bool operator=3D=3D(const TcgV &Other) const { return Other.Id =3D=3D = Id; } + bool operator!=3D(const TcgV &Other) const { return !operator=3D=3D(Ot= her); } + + // Print out struct fields, useful for debugging. + inline void dump(llvm::raw_ostream &Out) const { + Out << "TcgV " << Id; + if (!Name.empty()) { + Out << " (" << Name << ")"; + } + Out << ":\n"; + Out << " Kind: "; + switch (Kind) { + case IrInvalid: + Out << "IrInvalid\n"; + break; + case IrValue: + Out << "IrValue\n"; + break; + case IrImmediate: + Out << "IrImmediate\n"; + break; + case IrPtr: + Out << "IrPtr\n"; + break; + case IrPtrToOffset: + Out << "IrPtrToOffset\n"; + break; + case IrLabel: + Out << "IrLabel\n"; + break; + } + if (Kind =3D=3D IrPtrToOffset) { + Out << " VectorElementCount: " << (int)Size.Vec.ElementCount + << "\n"; + Out << " VectorElementBitWidth: " << (int)Size.Vec.ElementBit= Width + << "\n"; + } else { + Out << " TcgSize: " << (int)Size.Val.TcgBitWidth << "\n"; + Out << " LlvmSize: " << (int)Size.Val.LlvmBitWidth << "\n"; + } + Out << " ConstantExpression: " << ConstantExpression << "\n"; + } +}; + +// Helper function for verifying that a set of `TcgV` are of acceptable ty= pes, +// use with flags like +// +// assertKinds({{Dst, IrPtr}, {Src, IrValue | IrImmediate})) +// +inline void assertKinds(llvm::ArrayRef> Pai= rs) { + for (auto &[Tcg, Flag] : Pairs) { + assert(Tcg.Kind & Flag); + } +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785380976; cv=none; d=zohomail.com; s=zohoarc; b=YyQLmdybLFp3eg/BA3ZjimMCC4Qj78fX2rTZ0ZRlRFdPSBF9ljPOJyshp2Z/EWQP1hPns2lMY07nZMNL9w3NRO23wggrktXG4RVB1By5+9NK4W05YVPxKU/0CaGk59LxeO4mGen/KT1F+PDM021LUKnfhzaFPxT0yGM+xYTlShc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785380976; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=ykgq7m2MwXWBOItfqUBXCnnSV1ZKB1COoa7NuA2wPyE=; b=EUeWm6CahYsepD//SH8LLC80aHZPKQTvywrUOcYdI/wuAXIrhj5YeGg+siWTj+cpHY6GtXsBgPbpjHtuSLi4eeqEfG7eBS3co3R2ivt8FVgP+hSKX1jLYgh8AP0X8XlhZgClB1xfYEv3LqwH8OejT863E3Pj5jiKKkSAdMbVv/0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785380976576287.66270721531293; Wed, 29 Jul 2026 20:09:36 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH76-0004Qv-4t; Wed, 29 Jul 2026 23:07:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH72-0004FW-FA for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:12 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6s-0002xl-4s for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=ykgq7m2MwXWBOItfqUBXCnnSV1ZKB1COoa7NuA2wPyE=; b=Nd3NokSIDLPYJ/o YwR4bJWTmEfyHuH33xqrIIUNvn78iSD9IwywvNx7l67Hzb3gaDZfTaXjCRt6RSbLz6srD/kPvxByO XCq4wDDY70ru/lodstpWFYbU8VUhYV2+wtQB88ZPYPpX5bxndkHAqgACzborFo6AdgVJS7wylpo/R +s=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 30/50] helper-to-tcg: Introduce TcgGenPass Date: Thu, 30 Jul 2026 05:10:04 +0200 Message-ID: <20260730031025.12926-31-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785380977570158500 Content-Type: text/plain; charset="utf-8" Adds a final backend pass over the LLVM module, taking previously optimized and canonicalized LLVM IR and for each function: 1. Maps arguments, and propagates constant expressions; 2. Allocates TCG values to non-constants; 3. Emits the final TCG. Points above will be implemented in following commits, this commits adds boilerplate and some scaffolding for translating and emitting code. TODO: This commit could do with some more splitting, TcgEmit.hpp and ValueMapping.hpp and the functions therein are referenced but not added in this commit, they come later. Signed-off-by: Anton Johansson --- .../helper-to-tcg/include/CmdLineOptions.hpp | 16 + .../helper-to-tcg/include/TcgGenPass.hpp | 63 +++ subprojects/helper-to-tcg/meson.build | 1 + subprojects/helper-to-tcg/src/Pipeline.cpp | 97 ++++- .../src/TcgGenPass/TcgGenPass.cpp | 385 ++++++++++++++++++ 5 files changed, 561 insertions(+), 1 deletion(-) create mode 100644 subprojects/helper-to-tcg/include/TcgGenPass.hpp create mode 100644 subprojects/helper-to-tcg/src/TcgGenPass/TcgGenPass.cpp diff --git a/subprojects/helper-to-tcg/include/CmdLineOptions.hpp b/subproj= ects/helper-to-tcg/include/CmdLineOptions.hpp index 3a827f8ab7..1a4c0dd732 100644 --- a/subprojects/helper-to-tcg/include/CmdLineOptions.hpp +++ b/subprojects/helper-to-tcg/include/CmdLineOptions.hpp @@ -28,3 +28,19 @@ extern llvm::cl::opt TcgGlobalMappingsName; extern llvm::cl::opt UserPCRelBranchFunc; extern llvm::cl::opt UserPCRelBranchFallthroughFunc; extern llvm::cl::opt UserPCRelBranchConditionalFunc; +// Options for TcgEmit +extern llvm::cl::opt MmuIndexFunction; +extern llvm::cl::opt TempVectorBlock; +extern llvm::cl::opt MaxVectorInstructions; +extern llvm::cl::opt MaxVectorTempBytes; +// Options for MapTemporaries +extern llvm::cl::opt GuestPtrSize; +// Options for TcgGenPass +extern llvm::cl::opt OutputSourceFile; +extern llvm::cl::opt OutputHeaderFile; +extern llvm::cl::opt OutputEnabledFile; +extern llvm::cl::opt ErrorOnTranslationFailure; +extern llvm::cl::opt StaticOutput; +extern llvm::cl::opt AllowDeclCall; +extern llvm::cl::opt ForwardContext; +extern llvm::cl::opt EmitVectorPreamble; diff --git a/subprojects/helper-to-tcg/include/TcgGenPass.hpp b/subprojects= /helper-to-tcg/include/TcgGenPass.hpp new file mode 100644 index 0000000000..8318b2c7cd --- /dev/null +++ b/subprojects/helper-to-tcg/include/TcgGenPass.hpp @@ -0,0 +1,63 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include "DebugInfo.hpp" +#include "FunctionAnnotation.hpp" +#include "TcgGlobalMap.hpp" +#include "VectorLayout.hpp" + +#include + +// +// TcgGenPass +// +// Backend pass responsible for emitting the final TCG code. +// +// This pass is further diveded into smaller passes that map arguments, +// propagate constants, allocate registers, and emit finally TCG. +// +// Note, the incoming IR is broken and linearized to an array of basic blo= cks, +// which acts to simplify the various backend passes. +// + +class TcgGenPass : public llvm::PassInfoMixin { + llvm::raw_ostream &OutSource; + llvm::raw_ostream &OutHeader; + llvm::raw_ostream &OutHelpers; + llvm::raw_ostream &OutEnabled; + llvm::StringRef HeaderPath; + const AnnotationMapTy &Annotations; + const DebugInfoMapTy &DebugInfo; + const TcgGlobalMap &TcgGlobals; + const VectorLayout &VL; + + public: + TcgGenPass(llvm::raw_ostream &OutSource, llvm::raw_ostream &OutHeader, + llvm::raw_ostream &OutHelpers, llvm::raw_ostream &OutEnable= d, + llvm::StringRef HeaderPath, const AnnotationMapTy &Annotati= ons, + const DebugInfoMapTy &DebugInfo, const TcgGlobalMap &TcgGlo= bals, + const VectorLayout &VL) + : OutSource(OutSource), OutHeader(OutHeader), OutHelpers(OutHelper= s), + OutEnabled(OutEnabled), HeaderPath(HeaderPath), + Annotations(Annotations), DebugInfo(DebugInfo), + TcgGlobals(TcgGlobals), VL(VL) {} + + llvm::PreservedAnalyses run(llvm::Module &M, + llvm::ModuleAnalysisManager &MAM); +}; diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index c88c759ba6..880561416a 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -48,6 +48,7 @@ sources =3D [ 'src/PrepareForTcgPass/TransformGEPs.cpp', 'src/PrepareForTcgPass/CanonicalizeIR.cpp', 'src/PrepareForTcgPass/IdentityMap.cpp', + 'src/TcgGenPass/TcgGenPass.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/Pipeline.cpp b/subprojects/helpe= r-to-tcg/src/Pipeline.cpp index 9b45664bdc..6555762b9d 100644 --- a/subprojects/helper-to-tcg/src/Pipeline.cpp +++ b/subprojects/helper-to-tcg/src/Pipeline.cpp @@ -19,6 +19,7 @@ #include "LlvmCompat.hpp" #include "PrepareForOptPass.hpp" #include "PrepareForTcgPass.hpp" +#include "TcgGenPass.hpp" #include "VectorLayout.hpp" =20 #if LLVM_VERSION_MAJOR =3D=3D 15 @@ -46,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -105,7 +107,7 @@ cl::opt UserPCRelBranchFallthroughFunc( " from inside a conditional block, but that condition isn't t= aken." " and we instead need to fallthrough to the next instruction.= "), cl::init(""), cl::cat(Cat)); -=20 + static llvm::cl::opt VecForceBigEndian( "vec-force-big-endian", cl::desc("Force emission of vector operations as if on a big-endian ho= st."), @@ -127,6 +129,76 @@ static llvm::cl::opt VecLane0( "Vector lane 0 is in the most-significant bytes")= ), cl::init(LeastSignificant), cl::cat(Cat)); =20 +// Options for TcgEmit +cl::opt MmuIndexFunction( + "mmu-index-function", + cl::desc("Name of a (uint32_t tb_flag) -> int function returning the " + "mmu index from the tb_flags of the current translation block= "), + cl::init("get_tb_mmu_index"), cl::cat(Cat)); + +cl::opt + TempVectorBlock("temp-vector-block", + cl::desc("Name of uint8_t[...] field in CPUArchState u= sed " + "for allocating temporary gvec variables"), + cl::init("tmp_vmem"), cl::cat(Cat)); + +cl::opt MaxVectorTempBytes( + "max-vector-temp-bytes", + cl::desc("Maximum bytes to be allocated for vector temporaries"), + cl::init(0), cl::cat(Cat)); + +cl::opt MaxVectorInstructions( + "max-vector-instructions", + cl::desc( + "Maximum number of vector instructions an emitted function may hav= e"), + cl::init(0), cl::cat(Cat)); + +// Options for MapTemporaries +cl::opt + GuestPtrSize("guest-ptr-size", + cl::desc("Pointer size of the guest architecture"), + cl::init(32), cl::cat(Cat)); + +// Options for TcgGenPass +cl::opt OutputSourceFile("output-source", + cl::desc("output .c file"), + cl::init("helper-to-tcg-emitted.c"), + cl::cat(Cat)); + +cl::opt OutputHeaderFile("output-header", + cl::desc("output .h file"), + cl::init("helper-to-tcg-emitted.h"), + cl::cat(Cat)); + +cl::opt OutputHelpersFile( + "output-helpers", cl::desc("output support helper.h file"), + cl::init("helper-to-tcg-support-helpers.h"), cl::cat(Cat)); + +cl::opt + OutputEnabledFile("output-enabled", + cl::desc("output list of tranlated functions"), + cl::init("helper-to-tcg-enabled"), cl::cat(Cat)); + +cl::opt + ErrorOnTranslationFailure("error-on-translation-failure", + cl::desc("Abort translation on first failure= "), + cl::init(false), cl::cat(Cat)); + +cl::opt StaticOutput("static-output", + cl::desc("Statically define output functions"), + cl::init(false), cl::cat(Cat)); + +cl::opt + AllowDeclCall("allow-decl-call", + cl::desc("Forward calls to declared functions to output"= ), + cl::init(false), cl::cat(Cat)); + +cl::opt ForwardContext( + "forward-context", + cl::desc( + "Pass a DisasContext struct to all translated functions and calls"= ), + cl::init(false), cl::cat(Cat)); + // Define a TargetTransformInfo (TTI) subclass, this allows for overriding // common per-llvm-target information expected by other LLVM passes, such // as the width of the largest scalar/vector registers. Needed for consis= tent @@ -300,5 +372,28 @@ int main(int argc, char **argv) { MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } =20 + // + // Finally we run a backend pass that converts from LLVM IR to TCG, + // and emits the final code. + // + + std::error_code EC; + ToolOutputFile OutSource(OutputSourceFile, EC, compat::OpenFlags); + ToolOutputFile OutHeader(OutputHeaderFile, EC, compat::OpenFlags); + ToolOutputFile OutHelpers(OutputHelpersFile, EC, compat::OpenFlags); + ToolOutputFile OutEnabled(OutputEnabledFile, EC, compat::OpenFlags); + assert(!EC); + + MPM.addPass(TcgGenPass(OutSource.os(), OutHeader.os(), OutHelpers.os(), + OutEnabled.os(), OutputHeaderFile, Annotations, + DebugInfo, TcgGlobals, VL)); + + MPM.run(*M.get(), MAM); + + OutSource.keep(); + OutHeader.keep(); + OutHelpers.keep(); + OutEnabled.keep(); + return 0; } diff --git a/subprojects/helper-to-tcg/src/TcgGenPass/TcgGenPass.cpp b/subp= rojects/helper-to-tcg/src/TcgGenPass/TcgGenPass.cpp new file mode 100644 index 0000000000..a831a75204 --- /dev/null +++ b/subprojects/helper-to-tcg/src/TcgGenPass/TcgGenPass.cpp @@ -0,0 +1,385 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "TcgGenPass.hpp" +#include "CmdLineOptions.hpp" +#include "DebugInfo.hpp" +#include "Error.hpp" +#include "LinearizeBlocks.hpp" +#include "TcgEmit.hpp" +#include "TcgType.hpp" +#include "ValueMapping.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_TYPE "tcg-gen-pass" + +using namespace llvm; + +struct TranslatedFunction { + StringRef Name; + std::string Decl; + std::string Code; + std::string DispatchCode; + bool IsHelper; + bool HasVectorTemporaries; + bool NeedVectorSizeChangeOps; +}; + +static Expected +translateFunction(Module &M, FunctionAnalysisManager &FAM, Function *F, + const TcgGlobalMap &TcgGlobals, + const AnnotationMapTy &Annotations, + const DebugInfoMapTy &DebugInfo, + const SmallPtrSet HasTranslatedFunction)= { + assert(!F->isDeclaration()); + + TranslatedFunction TF =3D { + .Name =3D F->getName(), + }; + + { + // Remove prefix for helper functions to get cleaner emitted names + TF.IsHelper =3D TF.Name.consume_front("helper_"); + } + + std::string Body; + raw_string_ostream Out(Body); + CEmitter CE; + TcgEmitter TE(Out, CE); + TempAllocationData TAD; + + // Following block of function calls make up the majority of the backe= nd, + // the rest is mostly string emission. + { + // Linearize blocks, putting into a vector and breaking the LLVM I= R by + // some replacing branches with pseudo instructions. + const LinearBlocks Blocks =3D linearizeBlocks(M, FAM, *F); + LLVM_DEBUG({ + dbgs() << "Translating " << F->getName() << "\n"; + for (auto &BB : Blocks) { + dbgs() << *BB << "\n"; + } + }); + + // Map arguments to `TcgV`, store results in `TempAllocationData`. + if (auto Err =3D mapArguments(*F, Annotations, DebugInfo, TAD); Er= r) { + return Err; + } + + // Make a forward pass over the IR, and propagate constant express= ions + // forward, assigning them to values in `TempAllocationData`. + if (auto Err =3D propagateConstantExpressions(CE, *F, Blocks, Anno= tations, + DebugInfo, TcgGlobals,= TAD); + Err) { + return Err; + } + + // Make a backward pass over the IR and assign temporary `TcgV`s to + // non-constant expressions, attempt to reuse created temporaries. + // Mapped temporaries are stored in `TempAllocationData`. + if (auto Err =3D allocateTemporaries(*F, Blocks, Annotations, Debu= gInfo, + CE, TcgGlobals, TAD); + Err) { + return Err; + } + + // At this point all `Value`s in the function have been mapped to = either + // a temporary or a constant expression, with the exception of lab= els. + // Make a forward pass over the IR and emit the final TCG operatio= ns. + if (auto Err =3D mapTcgOperations(Blocks, TcgGlobals, Annotations, + HasTranslatedFunction, TAD, TE, CE= ); + Err) { + return Err; + } + } + + Out.flush(); + + raw_string_ostream OutFunc(TF.Code); + raw_string_ostream HeaderWriter(TF.Decl); + raw_string_ostream DispatchWriter(TF.DispatchCode); + std::string DispatchCall; + raw_string_ostream DispatchCallWriter(DispatchCall); + bool IsVectorInst =3D false; + + if (StaticOutput) { + HeaderWriter << "static "; + } + HeaderWriter << "void " << "emit_" << TF.Name << '('; + SmallVector CArgs; + + if (!F->getReturnType()->isVoidTy()) { + assert(TAD.hasReturnValue()); + IsVectorInst =3D (TAD.ReturnValue.Kind =3D=3D IrPtrToOffset); + CArgs.push_back(TAD.ReturnValue); + } + + for (const Argument &Arg : F->args()) { + TcgV T =3D TAD.Map[&Arg]; + IsVectorInst |=3D (T.Kind =3D=3D IrPtrToOffset); + CArgs.push_back(T); + } + + if (ForwardContext) { + HeaderWriter << "DisasContext *ctx"; + if (!CArgs.empty()) { + HeaderWriter << ", "; + } + } + + auto CArgIt =3D CArgs.begin(); + if (CArgIt !=3D CArgs.end()) { + HeaderWriter << TE.getType(*CArgIt) << ' ' << getName(*CArgIt); + ++CArgIt; + } + while (CArgIt !=3D CArgs.end()) { + HeaderWriter << ", " << TE.getType(*CArgIt) << ' ' << getName(*CAr= gIt); + ++CArgIt; + } + + if (!IsVectorInst) { + DispatchCallWriter << "emit_" << TF.Name << "("; + auto CArgIt =3D CArgs.begin(); + if (CArgIt !=3D CArgs.end()) { + DispatchWriter << "static inline void gen_helper_" << TF.Name + << "("; + for (int i =3D 0; i < CArgs.size(); ++i) { + if (i > 0) { + DispatchWriter << ", "; + } + DispatchWriter << TE.getType(TE.materialize(CArgs[i])) << = " " + << getName(CArgs[i]); + } + DispatchWriter << ")\n{\n"; + + DispatchWriter << "emit_" << TF.Name << "("; + for (int i =3D 0; i < CArgs.size(); ++i) { + if (i > 0) { + DispatchWriter << ", "; + } + if (CArgs[i].Kind =3D=3D IrImmediate) { + DispatchWriter << "tcgv_i" << CArgs[i].tcgBitWidth() + << "_temp(" << getName(CArgs[i]) << ")-= >val"; + } else { + DispatchWriter << getName(CArgs[i]); + } + } + DispatchWriter << ");\n}\n"; + } + } + + // Copy over function declaration from header to source file + HeaderWriter << ')'; + + OutFunc << "// " << *F->getReturnType() << ' ' << F->getName() << '\n'; + OutFunc << HeaderWriter.str(); + OutFunc << " {\n"; + OutFunc << Body; + OutFunc << "}\n"; + + HeaderWriter << ';'; + + if (MaxVectorTempBytes > 0 and + TE.allocatedVectorMemory() > MaxVectorTempBytes) { + return mkError(formatv("Uses too much vector memory: {0} > {1}", + TE.allocatedVectorMemory(), MaxVectorTempBy= tes) + .str()); + } + + if (MaxVectorInstructions > 0 and + TE.numVectorInstructions() > MaxVectorInstructions) { + return mkError(formatv("Uses too many vector instructions: {0} > {= 1}", + TE.numVectorInstructions(), + MaxVectorInstructions) + .str()); + } + + TF.HasVectorTemporaries =3D (TE.allocatedVectorMemory() > 0); + TF.NeedVectorSizeChangeOps =3D TE.NeedVectorSizeChangeOps; + + HeaderWriter.flush(); + DispatchWriter.flush(); + DispatchCallWriter.flush(); + + return TF; +} + +PreservedAnalyses TcgGenPass::run(Module &M, ModuleAnalysisManager &MAM) { + auto &CG =3D MAM.getResult(M); + auto &FAM =3D + MAM.getResult(M).getManager(); + + // Vector of translation results, order matters, lower indices are emi= tted + // higher up in the output file, and may be used by the higher indices. + SmallVector TranslatedFunctions; + // Two sets used for quickly looking up whether or not a function has + // already been translated, or the translation failed. + SmallPtrSet FailedToTranslateFunction; + SmallPtrSet HasTranslatedFunction; + bool NeedVectorMem =3D false; + bool NeedVectorSizeChangeOps =3D false; + for (Function &F : M) { + if (F.isDeclaration()) { + continue; + } + + // Depth first traversal of call graph. Needed to ensure called + // functions are translated before the current function. + CallGraphNode *Node =3D CG[&F]; + for (auto *N : make_range(po_begin(Node), po_end(Node))) { + Function *F =3D N->getFunction(); + + // If F in the call graph has already been translated and fail= ed, + // abort translation of the current function. + if (FailedToTranslateFunction.contains(F)) { + break; + } + + // Skip translation of invalid functions or functions that have + // already been translated. + if (!F or F->isDeclaration() or HasTranslatedFunction.contains= (F)) { + continue; + } + + // Reset variable IDs for the current function, since al TcgVs= are + // function-local. + TcgV::resetId(); + + auto Translated =3D + translateFunction(M, FAM, F, TcgGlobals, Annotations, Debu= gInfo, + HasTranslatedFunction); + if (!Translated) { + FailedToTranslateFunction.insert(F); + LLVM_DEBUG({ + dbgs() << F->getName() << ": " << Translated.takeError= () + << "\n"; + }); + if (ErrorOnTranslationFailure) { + return PreservedAnalyses::all(); + } + } else { + TranslatedFunctions.push_back(*Translated); + HasTranslatedFunction.insert(F); + NeedVectorMem |=3D Translated->HasVectorTemporaries; + NeedVectorSizeChangeOps |=3D Translated->NeedVectorSizeCha= ngeOps; + } + } + } + + // Preamble + OutSource << "#include \"qemu/osdep.h\"\n"; + OutSource << "#include \"qemu/log.h\"\n"; + OutSource << "#include \"cpu.h\"\n"; + OutSource << "#include \"translate.h\"\n"; + OutSource << "#include \"tcg/tcg-op.h\"\n"; + OutSource << "#include \"tcg/tcg-op-gvec.h\"\n"; + OutSource << "#include \"tcg/tcg.h\"\n"; + // OutSource << "#include \"exec/helper-gen.h\"\n"; + if (ForwardContext) { + OutSource << "#include \"translate.h\"\n"; + } + if (!StaticOutput) { + OutSource << "#include \"tcg/tcg-global-mappings.h\"\n"; + } + if (MmuIndexFunction.size() > 0) { + OutSource << "#include \"exec/translation-block.h\""; + } + OutSource << '\n'; + + if (!StaticOutput) { + OutSource << "#include \"" + << HeaderPath.substr(HeaderPath.find_last_of('/') + 1) + << "\"\n"; + OutSource << '\n'; + + // Emit extern definitions for all global TCGv_* that are mapped + // to the CPUState. + for (size_t TypeIndex =3D 0; TypeIndex < TcgGlobals.size(); ++Type= Index) { + for (auto &P : TcgGlobals[TypeIndex]) { + const TcgGlobal &Global =3D P.second; + auto Size =3D ValueSize::fromBitWidth(Global.Size); + assert(Size); + OutSource << "extern " << "TCGv_i" << (int)Size->TcgBitWid= th + << " " << Global.Code; + if (Global.NumElements > 1) { + OutSource << "[" << Global.NumElements << "]"; + } + OutSource << ";\n"; + } + } + } + + if (NeedVectorSizeChangeOps) { + emitVectorSizeChangeOps(OutSource, OutHelpers, VL); + } + + if (NeedVectorMem) { + emitVectorMem(OutSource); + } + + if (ForwardContext) { + OutHeader << "struct DisasContext;\n"; + OutHeader << "typedef struct DisasContext DisasContext;\n"; + OutSource << "#include \"translate.h\"\n"; + } + + // Emit translated functions + for (auto &TF : TranslatedFunctions) { + OutSource << TF.Code << '\n'; + OutHeader << TF.Decl << '\n'; + OutEnabled << TF.Name << '\n'; + } + + // Emit a dispatched to go from helper function address to our + // emitted code, if we succeeded. + OutHeader << "bool helper_to_tcg_dispatcher(void *func, TCGTemp *ret_t= emp, " + "int nargs, TCGTemp **args);\n"; + + OutHeader << "#include \"tcg/helper-info.h\"\n"; + OutHeader << "#include \"exec/helper-head.h.inc\"\n"; + for (Function &F : M) { + StringRef Name =3D F.getName(); + if (!Name.consume_front("helper_")) { + continue; + } + if (!HasTranslatedFunction.contains(&F)) { + SmallVector ArgTys; + for (auto &A : F.args()) { + ArgTys.push_back(A.getType()); + } + emitHelperGen(OutHeader, Name, F.getReturnType(), ArgTys); + } + } + for (TranslatedFunction &TF : TranslatedFunctions) { + OutHeader << TF.DispatchCode; + } + + return PreservedAnalyses::all(); +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381046; cv=none; d=zohomail.com; s=zohoarc; b=OElWZUeo2Q01JUv6TaFeIQFh4hldR4rDt73W327FxFk0qyTXe+V4tLhJmkYyuIRyqnkaCi3aXH1XvhywigytExFXAdcbYueCDLCAIZUZxBifsI2Lp8NnkKYD1tb2Gz9OgT4XboIEk79dJo/IGZSnZrwGXEdZc/4O3vtE0BOEOfc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381046; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=sa85oJBJiUNg1ScgRXz+lQi+m+/cKBsT1J3LdfOAYvQ=; b=IO/HciB2UEeybVamWHBNief9DHrEW4SUvB9FYU+VmWC9drhY+Ax3Xf4Y7mIRCeE0KG71GQEbb4bgvl3NwAiKGrzxJsrN55zsDVtyc5tjOskjDpPaoG24+UD2LZaLTRVNE6OQYkq99j4izMKN3xfIN/rbt2qT2m56go259jWDGj0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178538104611992.02100018695842; Wed, 29 Jul 2026 20:10:46 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7C-0004Xw-5c; Wed, 29 Jul 2026 23:07:23 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH74-0004Qr-CV for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:15 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6v-0002y6-EP for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=sa85oJBJiUNg1ScgRXz+lQi+m+/cKBsT1J3LdfOAYvQ=; b=g2SiWR4eSxdA1Ih u4SkXokLl8YQcFyyCFsOcYnPHD1cepI1e27u0Hp5UOa6Rtccz242sCW5i3QuNONYg+2ifBwgYNm8L UQ4X/QkMLUNe9mr6i2zr/Ta9XtHAMDcRCWawXIA2DbkagzhzePCzvc6gUwbuq/4ZdjKnFv5jczaDo Ro=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 31/50] helper-to-tcg: TcgGenPass, linearize basic blocks Date: Thu, 30 Jul 2026 05:10:05 +0200 Message-ID: <20260730031025.12926-32-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381047790158500 Content-Type: text/plain; charset="utf-8" Passes over the IR that will follow all depend on a specific iteration order over the IR that must match between passes, establish that iteration order. Also replace conditional branches with a pseudo instruction closer in semantics to TCG, this breaks the IR verification, but as this is the last transformation of the IR in this tool that's acceptable. Signed-off-by: Anton Johansson Reviewed-by: Alessandro Di Federico --- subprojects/helper-to-tcg/meson.build | 1 + .../src/TcgGenPass/LinearizeBlocks.cpp | 140 ++++++++++++++++++ .../src/TcgGenPass/LinearizeBlocks.hpp | 32 ++++ 3 files changed, 173 insertions(+) create mode 100644 subprojects/helper-to-tcg/src/TcgGenPass/LinearizeBlock= s.cpp create mode 100644 subprojects/helper-to-tcg/src/TcgGenPass/LinearizeBlock= s.hpp diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 880561416a..58e5f67153 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -49,6 +49,7 @@ sources =3D [ 'src/PrepareForTcgPass/CanonicalizeIR.cpp', 'src/PrepareForTcgPass/IdentityMap.cpp', 'src/TcgGenPass/TcgGenPass.cpp', + 'src/TcgGenPass/LinearizeBlocks.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/TcgGenPass/LinearizeBlocks.cpp b= /subprojects/helper-to-tcg/src/TcgGenPass/LinearizeBlocks.cpp new file mode 100644 index 0000000000..28dff1c572 --- /dev/null +++ b/subprojects/helper-to-tcg/src/TcgGenPass/LinearizeBlocks.cpp @@ -0,0 +1,140 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "LinearizeBlocks.hpp" +#include "PseudoInst.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace PatternMatch; + +// Needed to track and remove instructions not handled by a subsequent dea= d code +// elimination, this applies to calls to pseudo instructions in particular. +using EraseInstVec =3D SmallVector; + +static void convertICmpBrToPseudInst(LLVMContext &Context, RegionInfo &RI, + EraseInstVec &InstToErase, Module &M, + Instruction *I, BasicBlock *NextBB) { + auto *ICmp =3D dyn_cast(I); + if (!ICmp) { + return; + } + + // Since we want to remove the icmp instruction we ensure that + // all uses are branch instructions that can be converted into + // @brcond.* calls. + for (User *U : ICmp->users()) { + if (!isa(U)) { + return; + } + } + + Value *Op0 =3D ICmp->getOperand(0); + Value *Op1 =3D ICmp->getOperand(1); + auto *CmpIntTy =3D dyn_cast(Op0->getType()); + if (!CmpIntTy) { + return; + } + for (User *U : ICmp->users()) { + auto *Br =3D cast(U); + + BasicBlock *True =3D Br->getSuccessor(0); + BasicBlock *False =3D Br->getSuccessor(1); + + IRBuilder<> Builder(Br); + + // TODO: This is strange, indeally the unreachable branch should h= ave + // been optimized out, here we invert the conditional branch if we= can + // fallthrough to the reachable branch. + bool TrueUnreachable =3D + True->getTerminator()->getOpcode() =3D=3D Instruction::Unreach= able and + False->getTerminator()->getOpcode() !=3D Instruction::Unreacha= ble; + + // If the next basic block is either of our true/false + // branches, we can fallthrough instead of branching. + bool Fallthrough =3D (NextBB =3D=3D True or NextBB =3D=3D False); + + // If the succeeding basic block is the true branch we + // invert the condition so we can fallthrough instead. + ICmpInst::Predicate Predicate; + if (NextBB =3D=3D True or (TrueUnreachable and NextBB =3D=3D False= )) { + std::swap(True, False); + Predicate =3D ICmp->getInversePredicate(); + } else { + Predicate =3D ICmp->getPredicate(); + } + + createPseudoInstCall(M, Builder, Brcond, Builder.getVoidTy(), + {Builder.getInt8(Fallthrough), + ConstantInt::get(CmpIntTy, Predicate), Op0, = Op1, + True, False}); + + InstToErase.push_back(Br); + } + InstToErase.push_back(ICmp); +} + +LinearBlocks linearizeBlocks(Module &M, FunctionAnalysisManager &FAM, + Function &F) { + assert(!F.isDeclaration()); + + LinearBlocks Blocks{}; + + LLVMContext &Context =3D F.getContext(); + EraseInstVec InstToErase; + auto &RI =3D FAM.getResult(F); + + ReversePostOrderTraversal RPOT(&F); + for (auto BBIt =3D RPOT.begin(); BBIt !=3D RPOT.end(); ++BBIt) { + Blocks.push_back(*BBIt); + } + + for (int i =3D 0; i < Blocks.size(); ++i) { + BasicBlock *BB =3D Blocks[i]; + BasicBlock *NextBB =3D (i + 1 < Blocks.size()) ? Blocks[i + 1] : n= ullptr; + for (Instruction &I : *BB) { + convertICmpBrToPseudInst(Context, RI, InstToErase, M, &I, Next= BB); + } + } + + // Finally clean up instructions we need to remove manually + for (Instruction *I : InstToErase) { + I->eraseFromParent(); + } + + return Blocks; +} diff --git a/subprojects/helper-to-tcg/src/TcgGenPass/LinearizeBlocks.hpp b= /subprojects/helper-to-tcg/src/TcgGenPass/LinearizeBlocks.hpp new file mode 100644 index 0000000000..8d9a1afc54 --- /dev/null +++ b/subprojects/helper-to-tcg/src/TcgGenPass/LinearizeBlocks.hpp @@ -0,0 +1,32 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include +#include + +namespace llvm { +class BasicBlock; +class Function; +class Module; +} // namespace llvm + +using LinearBlocks =3D llvm::SmallVector; +LinearBlocks linearizeBlocks(llvm::Module &M, + llvm::FunctionAnalysisManager &FAM, + llvm::Function &F); --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381009; cv=none; d=zohomail.com; s=zohoarc; b=MlZmqUS0j3o2dnu1I8r+QVTF/DhIHu6HQQPonUsxM5jqvjfcXu1PJHDS9B9MUmYCiPnp+7WUf05d5nqWhqNE0fQ9J1chmrXYimDN1e/uvHSlIRlTADXFSBf2X276NukB/FAa1cnEVs/I37MLUyJ7pRa/rEL6zqRJHgmJZylPeWk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381009; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=k5urcBZVM2TfT4WmoKyPbJ6vR9r6kPTv/KQ5gTC9i7Y=; b=kKndsVlQvowchqQM6+dQUvylyvrF7Narzrp8XHeThje5NqbADC8N+BaZE45txHq2G1rk23DHq7xesFjyhmhW8TtlBv3xOiz8dk1bq0lUwLn53UeiHmOWyqsQnCwSJfkmT+rrFbpU8DbjIN4YKFDoB8M04PlYvemr7M1IaO2LD+U= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381009015326.4409673268649; Wed, 29 Jul 2026 20:10:09 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7F-0004c5-RF; Wed, 29 Jul 2026 23:07:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH72-0004Fc-Gj for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:12 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6x-0002yE-HK for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=k5urcBZVM2TfT4WmoKyPbJ6vR9r6kPTv/KQ5gTC9i7Y=; b=A4lyiEiA2hB6iQl uIqZIt0fXDyP0zx6TN14Rcd+3FmDgbK0cDieaFbk1InXNPx59R0hTQgIOuhDPwjpV2EfozhyS02F9 SdauzE9nK8/hBrCOhgpdVdmeHaBzPubmNRNelrlySF7raCQ5YGKYeLp0J7Dxy8mKT1OkQM/of2y6I /s=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 32/50] helper-to-tcg: TcgGenPass, introduce Value <-> TcgV map Date: Thu, 30 Jul 2026 05:10:06 +0200 Message-ID: <20260730031025.12926-33-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381009620158500 Content-Type: text/plain; charset="utf-8" Adds a `TempAllocationData` structure which will be the primary struct holding information about mappings between `Value`s and `TcgV`s. Any identified return value is also stored along with flags for easier use by other passes. All functions which populate `TempAllocationData` will be declared in this header. Signed-off-by: Anton Johansson --- .../src/TcgGenPass/ValueMapping.hpp | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 subprojects/helper-to-tcg/src/TcgGenPass/ValueMapping.h= pp diff --git a/subprojects/helper-to-tcg/src/TcgGenPass/ValueMapping.hpp b/su= bprojects/helper-to-tcg/src/TcgGenPass/ValueMapping.hpp new file mode 100644 index 0000000000..6aaf8acaf3 --- /dev/null +++ b/subprojects/helper-to-tcg/src/TcgGenPass/ValueMapping.hpp @@ -0,0 +1,110 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include "DebugInfo.hpp" +#include "FunctionAnnotation.hpp" +#include "LinearizeBlocks.hpp" +#include "TcgEmit.hpp" +#include "TcgGlobalMap.hpp" +#include "TcgType.hpp" + +#include +#include +#include +#include +#include + +// +// Value Mapping +// +// Data structures and functions needed for mapping various LLVM `Value`s = to +// `TcgV`s. +// + +namespace llvm { +class Function; +} + +// Flags reprensting common special cases for function return values, used= when +// emitted TCG to produce better output. +enum TempAllocationFlags { + SkipReturnMov =3D 1, + ReturnsImmediate =3D 2, + ReturnsValue =3D 4, + + HasReturn =3D (ReturnsImmediate | ReturnsValue), +}; + +// Main data structure responsible for holding mappings between LLVM `Valu= e`s +// and `TcgV`s, populated by functions declared below. +struct TempAllocationData { + // Mapping of LLVM Values to the corresponding TcgV + llvm::DenseMap Map; + + // Whether or not the final mov in an instruction can safely + // be ignored or not. + uint8_t flags =3D 0; + TcgV ReturnValue; + + inline bool hasReturnValue() const { return flags & HasReturn; } + + inline TcgV map(const llvm::Value *V, const TcgV &T) { + return Map.try_emplace(V, T).first->second; + } +}; + +inline const llvm::iterator_range +getOperands(const llvm::Instruction *const I) { + switch (I->getOpcode()) { + case Instruction::GetElementPtr: + return llvm::cast(I)->operands(); + case Instruction::Call: + return llvm::cast(I)->args(); + default: + return I->operands(); + } +} + +// Defined in MapArguments.cpp +llvm::Error mapArguments(const llvm::Function &F, + const AnnotationMapTy &AnnotationMap, + const DebugInfoMapTy &DebugInfo, + TempAllocationData &TAD); + +// Defined in MapConstantExpressions.cpp +llvm::Error propagateConstantExpressions(CEmitter &C, const llvm::Function= &F, + const LinearBlocks &Blocks, + const AnnotationMapTy &Annotation= Map, + const DebugInfoMapTy &DebugInfo, + const TcgGlobalMap &TcgGlobals, + TempAllocationData &TAD); +// Defined in MapTemporaries.cpp +llvm::Error allocateTemporaries(const llvm::Function &F, + const LinearBlocks &Blocks, + const AnnotationMapTy &AnnotationMap, + const DebugInfoMapTy &DebugInfo, CEmitter = &C, + const TcgGlobalMap &TcgGlobal, + TempAllocationData &TAD); + +// Defined MapTcgOperations.cpp +llvm::Error mapTcgOperations( + const LinearBlocks &Blocks, const TcgGlobalMap &TcgGlobals, + const AnnotationMapTy &AnnotationMap, + const llvm::SmallPtrSet &HasTranslatedFunction, + const TempAllocationData &TAD, TcgEmitter &Tcg, CEmitter &C); --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381074; cv=none; d=zohomail.com; s=zohoarc; b=jcXEtxmfxs3NCwRfIYCHWt2VIsfOokrj5IMIsmYRH62+6FF8F2f+FD05GMyhX9MKjpqcvfKZrocRfilkK+8Ew2OZItxEDjTQw+bET8qBHF8yRHtw4VFJN38dSbrWHh5i8uRI4fxwpWZ3B99+XXXZHv2SS0nLN2FoMKVJpVitLFs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381074; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=rMhWtm9d1KNItywPdae+4X897KHvmL4Z2sSDMS5a+EM=; b=JwCdyGMsihlxgoHqb0KK7JmZnKCqqxCmtJp28I+LJsPCbhx52U4uDxTXS0VVPRv3DuxwMJu3Pre6pq0tPg+ReM+f/NrQ7hwpnUI5Fw9VkoZvgbQP4lnev8MFZqbLMhX+FuTqOmODIJAamgRUaKrHnmqjMlXuHqayaasEF/mpW9E= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381074049476.9814248256424; Wed, 29 Jul 2026 20:11:14 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7i-0005bN-JS; Wed, 29 Jul 2026 23:07:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH78-0004Tw-8A for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:19 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6x-0002yH-HZ for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:16 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=rMhWtm9d1KNItywPdae+4X897KHvmL4Z2sSDMS5a+EM=; b=xRM3cW7JgXVVuYG JoXfeBm3MpujUZ31FiX1SnEIXnWwPXn3HgHAvlOqD7c5Fv/m5CQ5fOst2t5rHaLXSGa2kNxf9a/VC fttsrCPk5KFQ8NaLNi2B4l2SpQsxU5n1FAa2A6TWHPfWIjlxCwefMhbRPPMpty6FUKYAL3MWI2m6I h8=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 33/50] helper-to-tcg: TcgGenPass, add structs for string emission Date: Thu, 30 Jul 2026 05:10:07 +0200 Message-ID: <20260730031025.12926-34-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381076044158500 Content-Type: text/plain; charset="utf-8" Adds two new structures `TcgEmitter` and `CEmitter` with the purpose of producing valid TCG and C expressions in string form, these will be used in following commits. Signed-off-by: Anton Johansson --- subprojects/helper-to-tcg/meson.build | 1 + .../helper-to-tcg/src/TcgGenPass/TcgEmit.cpp | 1203 +++++++++++++++++ .../helper-to-tcg/src/TcgGenPass/TcgEmit.hpp | 315 +++++ 3 files changed, 1519 insertions(+) create mode 100644 subprojects/helper-to-tcg/src/TcgGenPass/TcgEmit.cpp create mode 100644 subprojects/helper-to-tcg/src/TcgGenPass/TcgEmit.hpp diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 58e5f67153..c03a4d5df6 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -50,6 +50,7 @@ sources =3D [ 'src/PrepareForTcgPass/IdentityMap.cpp', 'src/TcgGenPass/TcgGenPass.cpp', 'src/TcgGenPass/LinearizeBlocks.cpp', + 'src/TcgGenPass/TcgEmit.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/TcgGenPass/TcgEmit.cpp b/subproj= ects/helper-to-tcg/src/TcgGenPass/TcgEmit.cpp new file mode 100644 index 0000000000..8a39fd2589 --- /dev/null +++ b/subprojects/helper-to-tcg/src/TcgGenPass/TcgEmit.cpp @@ -0,0 +1,1203 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "TcgEmit.hpp" +#include "CmdLineOptions.hpp" +#include "TcgType.hpp" +#include "VectorLayout.hpp" + +#include + +using namespace llvm; + +// Function returning a TcgV representing the current MMU index. +// Needed for memory operations. +static const TcgV mmuindex() { + if (ForwardContext) { + return TcgV::makeImmediate("ctx->mem_idx", {T32, I32}); + } else { + return TcgV::makeImmediate( + MmuIndexFunction + "(tcg_ctx->gen_tb->flags)", {T32, I32}); + } +} + +// +// TcgEmitter private functions +// + +void TcgEmitter::genVecUnaryCall(StringRef Name, int ElementSize, + const TcgV &Dst, const TcgV &Src, + const TcgV &Size) { + Out << Name << "(MO_" << ElementSize << ", " << getName(Dst) << ", " + << getName(Src) << ", " << getName(Size) << ", " << getName(Size) + << ");\n"; + + // Track number of vector operations + ++NumVectorInstructions; +} + +void TcgEmitter::genVecBinaryCall(StringRef Name, int ElementSize, + const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1, size_t Size) { + Out << Name << "(MO_" << ElementSize << ", " << getName(Dst) << ", " + << getName(Src0) << ", " << getName(Src1) << Size << ", " << Size + << ");\n"; +} + +void TcgEmitter::genVecCall(StringRef Name, llvm::ArrayRef Arg= s, + const VectorSize OpSize, const VectorSize MaxS= ize) { + Out << "tcg_gen_gvec_" << Name << "(MO_" << (int)OpSize.ElementBitWidth + << ", "; + emitArgListTcg(Args.begin(), Args.end()); + Out << ", " << OpSize.bytes() << ", " << MaxSize.bytes() << ");\n"; + ++NumVectorInstructions; +} + +const std::string TcgEmitter::getType(const TcgV &Value) { + switch (Value.Kind) { + case IrValue: + return Twine("TCGv_i").concat(Twine(Value.tcgBitWidth())).str(); + case IrImmediate: + if (Value.tcgBitWidth() =3D=3D 1) { + return "bool"; + } else { + return C.intType(false, Value.llvmBitWidth()); + } + case IrPtr: + return "TCGv_ptr"; + case IrPtrToOffset: + return "intptr_t"; + case IrLabel: + return "TCGLabel *"; + default: + abort(); + } +} + +inline StringRef mapPredicate(const CmpInst::Predicate &Pred) { + switch (Pred) { + case CmpInst::ICMP_EQ: + return "TCG_COND_EQ"; + case CmpInst::ICMP_NE: + return "TCG_COND_NE"; + case CmpInst::ICMP_UGT: + return "TCG_COND_GTU"; + case CmpInst::ICMP_UGE: + return "TCG_COND_GEU"; + case CmpInst::ICMP_ULT: + return "TCG_COND_LTU"; + case CmpInst::ICMP_ULE: + return "TCG_COND_LEU"; + case CmpInst::ICMP_SGT: + return "TCG_COND_GT"; + case CmpInst::ICMP_SGE: + return "TCG_COND_GE"; + case CmpInst::ICMP_SLT: + return "TCG_COND_LT"; + case CmpInst::ICMP_SLE: + return "TCG_COND_LE"; + default: + abort(); + } +} + +static std::string mapBinOp(const Instruction::BinaryOps &Opcode, + const TcgV &Src0, const TcgV &Src1) { + const bool IsImmediate =3D + (Src0.Kind =3D=3D IrImmediate or Src1.Kind =3D=3D IrImmediate); + // TODO: + const bool IsPtr =3D (Opcode =3D=3D Instruction::Add and + (Src0.Kind =3D=3D IrPtr or Src1.Kind =3D=3D IrPtr)= ); + assert(IsImmediate or Src0.tcgBitWidth() =3D=3D Src1.tcgBitWidth()); + std::string Expr =3D ""; + llvm::raw_string_ostream ExprStream(Expr); + + // Check for valid boolean operations if operating on a boolean + if (Src0.llvmBitWidth() =3D=3D 1) { + assert(Src1.llvmBitWidth() =3D=3D 1); + switch (Opcode) { + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + break; + default: + abort(); + } + } + + switch (Opcode) { + case Instruction::Add: + ExprStream << "tcg_gen_add"; + break; + case Instruction::Sub: + ExprStream << "tcg_gen_sub"; + break; + case Instruction::And: + ExprStream << "tcg_gen_and"; + break; + case Instruction::Or: + ExprStream << "tcg_gen_or"; + break; + case Instruction::Xor: + ExprStream << "tcg_gen_xor"; + break; + case Instruction::Mul: + ExprStream << "tcg_gen_mul"; + break; + case Instruction::UDiv: + ExprStream << "tcg_gen_divu"; + break; + case Instruction::SDiv: + ExprStream << "tcg_gen_div"; + break; + case Instruction::AShr: + ExprStream << "tcg_gen_sar"; + break; + case Instruction::LShr: + ExprStream << "tcg_gen_shr"; + break; + case Instruction::Shl: + ExprStream << "tcg_gen_shl"; + break; + default: + abort(); + } + + if (IsImmediate) { + ExprStream << "i"; + } + + if (IsPtr) { + ExprStream << "_ptr"; + } else { + ExprStream << "_i" << (int)Src0.tcgBitWidth(); + } + + ExprStream.flush(); + + return Expr; +} + +static std::string mapVecBinOp(const Instruction::BinaryOps &Opcode, + const TcgV &Src0, const TcgV &Src1) { + const bool IsShift =3D Opcode =3D=3D Instruction::Shl or + Opcode =3D=3D Instruction::LShr or + Opcode =3D=3D Instruction::AShr; + + std::string Suffix; + switch (Src1.Kind) { + case IrPtrToOffset: + Suffix =3D (IsShift) ? "v" : ""; + break; + case IrValue: + Suffix =3D "s"; + break; + case IrImmediate: + Suffix =3D "i"; + break; + default: + abort(); + } + + switch (Opcode) { + case Instruction::Add: + return "add" + Suffix; + case Instruction::Sub: + return "sub" + Suffix; + case Instruction::Mul: + return "mul" + Suffix; + case Instruction::And: + return "and" + Suffix; + case Instruction::Or: + return "or" + Suffix; + case Instruction::Xor: + return "xor" + Suffix; + case Instruction::Shl: + return "shl" + Suffix; + case Instruction::LShr: + return "shr" + Suffix; + case Instruction::AShr: + return "sar" + Suffix; + default: + abort(); + } +} + +void TcgEmitter::genSetLabel(const TcgV &L) { + assert(L.Kind =3D=3D IrLabel); + Out << "gen_set_label(" << getName(L) << ");\n"; +} + +void TcgEmitter::defineNewTemp(const TcgV &Tcg) { + assert(!Tcg.ConstantExpression); + if (Tcg.Kind =3D=3D IrPtrToOffset and !EmittedVectorMem) { + EmittedVectorMem =3D true; + Out << "VectorMem mem =3D {0};\n"; + } + Out << getType(Tcg) << " " << getName(Tcg) << " =3D "; + switch (Tcg.Kind) { + case IrValue: + Out << "tcg_temp_new_i" << (int)Tcg.tcgBitWidth() << "();\n"; + break; + case IrPtr: + Out << "tcg_temp_new_ptr();\n"; + break; + case IrPtrToOffset: + AllocatedVectorMemory +=3D Tcg.vecSize().bytes(); + Out << "temp_new_gvec(&mem, " << Tcg.vecSize().bytes() << ");\n"; + break; + case IrLabel: + Out << "gen_new_label();\n"; + break; + default: + abort(); + } +} + +void TcgEmitter::genBr(const TcgV &L) { + assert(L.Kind =3D=3D IrLabel); + Out << "tcg_gen_br(" << getName(L) << ");\n"; +} + +void TcgEmitter::genExts(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrValue}}); + StackTwine<64> FuncStr =3D Twine("tcg_gen_ext") + Twine(Src.llvmBitWid= th()) + + "s_i" + Twine(Dst.tcgBitWidth()); + emitCallTcg(FuncStr, {Dst, Src}); +} + +void TcgEmitter::genExtI32I64(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrValue}}); + emitCallTcg("tcg_gen_ext_i32_i64", {Dst, Src}); +} + +void TcgEmitter::genExtrlI64I32(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrValue}}); + emitCallTcg("tcg_gen_extrl_i64_i32", {Dst, Src}); +} + +void TcgEmitter::genExtuI32I64(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrValue}}); + emitCallTcg("tcg_gen_extu_i32_i64", {Dst, Src}); +} + +void TcgEmitter::genExtrhI64I32(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrValue}}); + emitCallTcg("tcg_gen_extrh_i64_i32", {Dst, Src}); +} + +void TcgEmitter::genExtract(bool Sign, const TcgV &Dst, const TcgV &Src, + const TcgV &Offset, const TcgV &Length) { + assertKinds({{Dst, IrValue}, + {Src, IrValue | IrImmediate}, + {Offset, IrImmediate}, + {Length, IrImmediate}}); + assert(Dst.tcgBitWidth() =3D=3D Src.tcgBitWidth()); + const char *SignStr =3D (Sign) ? "s" : ""; + const TcgV MSrc =3D materialize(Src); + Out << "if (" << getName(Length) << " > 0) {\n"; + Out << "tcg_gen_" << SignStr << "extract_i" << (int)Dst.tcgBitWidth() + << "("; + emitArgListTcg({Dst, MSrc, Offset, Length}); + Out << ");\n"; + Out << "}\n"; +} + +void TcgEmitter::genDeposit(const TcgV &Dst, const TcgV &Into, + const TcgV &Offset, const TcgV &Length, + const TcgV &From) { + assertKinds({{Dst, IrValue}, + {Into, IrValue | IrImmediate}, + {From, IrValue | IrImmediate}, + {Offset, IrImmediate}, + {Length, IrImmediate}}); + assert(Dst.tcgBitWidth() =3D=3D Into.tcgBitWidth()); + assert(Dst.tcgBitWidth() =3D=3D From.tcgBitWidth()); + Out << "if (" << getName(Length) << " > 0) {\n"; + Out << "tcg_gen_deposit_i" << (int)Dst.tcgBitWidth() << "("; + const TcgV MInto =3D materialize(Into); + const TcgV MFrom =3D materialize(From); + emitArgListTcg({Dst, MInto, MFrom, Offset, Length}); + Out << ");\n"; + Out << "}\n"; +} + +void TcgEmitter::genPtrToValue(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrPtr}}); + if (Dst.tcgBitWidth() =3D=3D 64) { + emitCallTcg("tcg_gen_ext_ptr_i64", {Dst, Src}); + } else { + emitCallTcg("tcg_gen_trunc_ptr_i32", {Dst, Src}); + } +} + +void TcgEmitter::genValueToPtr(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrPtr}, {Src, IrValue}}); + if (Src.tcgBitWidth() =3D=3D 64) { + emitCallTcg("tcg_gen_trunc_i64_ptr", {Dst, Src}); + } else { + emitCallTcg("tcg_gen_trunc_i32_ptr", {Dst, Src}); + } +} + +void TcgEmitter::genConcat(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1) { + assertKinds({{Dst, IrValue}, {Src0, IrValue}, {Src1, IrValue}}); + emitCallTcg("tcg_gen_concat_i32_i64", {Dst, Src0, Src1}); +} + +void TcgEmitter::genMov(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrValue | IrImmediate}}); + assert(Dst.tcgBitWidth() =3D=3D Src.tcgBitWidth()); + const char *ImmStr =3D (Src.Kind =3D=3D IrImmediate) ? "i" : ""; + Out << "tcg_gen_mov" << ImmStr << "_i" << (int)Dst.tcgBitWidth() << "(" + << getName(Dst) << ", " << getName(Src) << ");\n"; +} + +void TcgEmitter::genMovPtr(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrPtr}, {Src, IrPtr}}); + Out << "tcg_gen_mov_ptr(" << getName(Dst) << ", " << getName(Src) << "= );\n"; +} + +void TcgEmitter::genAddPtr(const TcgV &Dst, const TcgV &Ptr, + const TcgV &Offset) { + assertKinds({{Dst, IrPtr}, {Ptr, IrPtr}}); + switch (Offset.Kind) { + case IrPtrToOffset: + case IrImmediate: { + emitCallTcg("tcg_gen_addi_ptr", {Dst, Ptr, Offset}); + } break; + case IrPtr: { + emitCallTcg("tcg_gen_add_ptr", {Dst, Ptr, Offset}); + } break; + case IrValue: { + auto OffsetPtr =3D TcgV::makeTemp({}, IrPtr); + defineNewTemp(OffsetPtr); + genValueToPtr(OffsetPtr, Offset); + emitCallTcg("tcg_gen_add_ptr", {Dst, Ptr, OffsetPtr}); + } break; + default: + abort(); + } +} + +void TcgEmitter::genBinOp(const TcgV &Dst, const Instruction::BinaryOps Op= code, + const TcgV &Src0, const TcgV &Src1) { + auto OpStr =3D mapBinOp(Opcode, Src0, Src1); + emitCallTcg(OpStr, {Dst, Src0, Src1}); +} + +void TcgEmitter::genMovcond(const CmpInst::Predicate &Pred, const TcgV &Re= t, + const TcgV &C1, const TcgV &C2, const TcgV &V1, + const TcgV &V2) { + const size_t OpWidth =3D Ret.tcgBitWidth(); + assert(OpWidth =3D=3D C1.tcgBitWidth()); + assert(OpWidth =3D=3D C2.tcgBitWidth()); + assert(OpWidth =3D=3D V1.tcgBitWidth()); + assert(OpWidth =3D=3D V2.tcgBitWidth()); + const TcgV mC1 =3D materialize(C1); + const TcgV mC2 =3D materialize(C2); + const TcgV mV1 =3D materialize(V1); + const TcgV mV2 =3D materialize(V2); + Out << "tcg_gen_movcond_i" << OpWidth << '(' << mapPredicate(Pred) << = ", "; + emitArgListTcg({Ret, mC1, mC2, mV1, mV2}); + Out << ");\n"; +} + +void TcgEmitter::genSetcond(const CmpInst::Predicate &Pred, const TcgV &Ds= t, + const TcgV &Src0, const TcgV &Src1) { + assertKinds( + {{Dst, IrValue}, {Src0, IrValue}, {Src1, IrValue | IrImmediate}}); + const size_t OpWidth =3D Dst.tcgBitWidth(); + assert(OpWidth =3D=3D Src0.tcgBitWidth()); + assert(OpWidth =3D=3D Src1.tcgBitWidth()); + const char *ImmStr =3D (Src1.Kind =3D=3D IrImmediate) ? "i" : ""; + Out << "tcg_gen_setcond" << ImmStr << "_i" << OpWidth; + Out << "(" << mapPredicate(Pred) << ", "; + emitArgListTcg({Dst, Src0, Src1}); + Out << ");\n"; +} + +void TcgEmitter::genBrcond(const CmpInst::Predicate &Pred, const TcgV &Src= 0, + const TcgV &Src1, const TcgV &Label) { + assertKinds({{Src0, IrValue | IrImmediate}, + {Src1, IrValue | IrImmediate}, + {Label, IrLabel}}); + assert(Src0.tcgBitWidth() =3D=3D Src1.tcgBitWidth()); + const char *ImmStr =3D (Src1.Kind =3D=3D IrImmediate) ? "i" : ""; + Out << "tcg_gen_brcond" << ImmStr << "_i" << (int)Src0.tcgBitWidth(); + Out << "(" << mapPredicate(Pred) << ", "; + emitArgListTcg({materialize(Src0), Src1, Label}); + Out << ");\n"; +} + +std::string TcgEmitter::getMemOp(uint8_t Size, uint8_t Endianness, + uint8_t Sign) { + std::string MemOpStr{}; + raw_string_ostream MemOpStream(MemOpStr); + MemOpStream << "MO_" << (int)8 * Size; + switch (Endianness) { + case 0: + break; // do nothing + case 1: + MemOpStream << " | MO_LE"; + break; + case 2: + MemOpStream << " | MO_BE"; + break; + default: + abort(); + } + switch (Sign) { + case 0: + break; + case 1: + MemOpStream << " | MO_SIGN"; + break; + default: + abort(); + } + return MemOpStream.str(); +} + +void TcgEmitter::genGuestLoad(const TcgV &Dst, const TcgV &Ptr, + StringRef MemOp) { + assertKinds({{Dst, IrValue}, {Ptr, IrValue | IrImmediate}}); + Out << "tcg_gen_qemu_ld_i" << (int)Dst.tcgBitWidth() << "("; + emitArgListTcg({Dst, materialize(Ptr), mmuindex()}); + Out << ", " << MemOp << ");\n"; +} + +void TcgEmitter::genGuestStore(const TcgV &Ptr, const TcgV &Src, + StringRef MemOp) { + assertKinds({{Ptr, IrValue | IrImmediate}, {Src, IrValue | IrImmediate= }}); + Out << "tcg_gen_qemu_st_i" << (int)Src.tcgBitWidth() << "("; + emitArgListTcg({materialize(Src), materialize(Ptr), mmuindex()}); + Out << ", " << MemOp << ");\n"; +} + +void TcgEmitter::genHostLoad(const TcgV &Dst, const TcgV &Ptr, + const TcgV &Offset) { + assertKinds({{Dst, IrValue}, {Ptr, IrPtr}}); + const size_t LlvmSize =3D Dst.llvmBitWidth(); + const size_t TcgSize =3D Dst.tcgBitWidth(); + if (LlvmSize < TcgSize) { + Out << "tcg_gen_ld" << LlvmSize << "u_i" << TcgSize; + } else { + Out << "tcg_gen_ld_i" << TcgSize; + } + Out << "("; + emitArgListTcg({Dst, Ptr, Offset}); + Out << ");\n"; +} + +void TcgEmitter::genHostLoadFromVec(const TcgV &Dst, const TcgV &Offset) { + genHostLoad(Dst, getGlobalEnv(), Offset); +} + +void TcgEmitter::genHostStore(const TcgV &Ptr, const TcgV &Src) { + assertKinds({{Ptr, IrPtr}, {Src, IrValue | IrImmediate}}); + const size_t LlvmSize =3D Src.llvmBitWidth(); + const size_t TcgSize =3D Src.tcgBitWidth(); + if (LlvmSize < TcgSize) { + Out << "tcg_gen_st" << LlvmSize << "_i" << TcgSize; + } else { + Out << "tcg_gen_st_i" << TcgSize; + } + Out << "("; + emitArgListTcg({materialize(Src), Ptr}); + Out << ", 0);\n"; +} +void TcgEmitter::genFunnelShl(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1, const TcgV &Shift) { + const size_t OpWidth =3D Dst.tcgBitWidth(); + assert(OpWidth =3D=3D Src0.tcgBitWidth()); + assert(OpWidth =3D=3D Src1.tcgBitWidth()); + assert(OpWidth =3D=3D Shift.tcgBitWidth()); + if (OpWidth =3D=3D 32) { + auto Temp =3D TcgV::makeTemp({T64, I64}, IrValue); + defineNewTemp(Temp); + genConcat(Temp, Src1, Src0); + + if (Shift.Kind =3D=3D IrImmediate) { + genBinOp(Temp, Instruction::Shl, Temp, Shift); + } else { + auto Ext =3D TcgV::makeTemp({T64, I64}, IrValue); + defineNewTemp(Ext); + genExtuI32I64(Ext, Shift); + genBinOp(Temp, Instruction::Shl, Temp, Ext); + } + + genExtrhI64I32(Dst, Temp); + } else { + genCallHelper( + "helper_fshl_i64", + {Dst, materialize(Src0), materialize(Src1), materialize(Shift)= }); + } +} + +void TcgEmitter::genBitreverse(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrValue}}); + StackTwine<64> FuncName =3D Twine("helper_bitreverse") + + Twine(Dst.tcgBitWidth()) + "_i" + + Twine(Src.tcgBitWidth()); + genCallHelper(FuncName, {Dst, Src}); +} + +void TcgEmitter::genCountLeadingZeros(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrValue}}); + assert(Dst.tcgBitWidth() =3D=3D Src.tcgBitWidth()); + Out << "tcg_gen_clzi_i" << Dst.tcgBitWidth() << "("; + emitArgListTcg({Dst, Src}); + Out << ", " << Src.tcgBitWidth() << ");\n"; +} + +void TcgEmitter::genCountTrailingZeros(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrValue}}); + assert(Dst.tcgBitWidth() =3D=3D Src.tcgBitWidth()); + Out << "tcg_gen_ctzi_i" << Dst.tcgBitWidth() << "("; + emitArgListTcg({Dst, Src}); + Out << ", " << Src.tcgBitWidth() << ");\n"; +} + +void TcgEmitter::genCountOnes(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrValue}}); + assert(Dst.tcgBitWidth() =3D=3D Src.tcgBitWidth()); + Out << "tcg_gen_ctpop_i" << Dst.tcgBitWidth() << "("; + emitArgListTcg({Dst, Src}); + Out << ");\n"; +} + +void TcgEmitter::genByteswap(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrValue}, {Src, IrValue}}); + assert(Dst.tcgBitWidth() =3D=3D Src.tcgBitWidth()); + Out << "tcg_gen_bswap" << Dst.llvmBitWidth() << "_i" << Src.tcgBitWidt= h() + << "("; + emitArgListTcg({Dst, Src}); + Out << ");\n"; +} + +void TcgEmitter::genUnsignedSatSub(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1) { + assertKinds({{Dst, IrValue}, {Src0, IrValue}, {Src1, IrValue}}); + const size_t OpWidth =3D Dst.tcgBitWidth(); + assert(OpWidth =3D=3D Src0.tcgBitWidth()); + assert(OpWidth =3D=3D Src1.tcgBitWidth()); + Out << "tcg_gen_ussub_i" << OpWidth << "("; + emitArgListTcg({Dst, Src0, Src1}); + Out << ");\n"; +} + +inline TcgKind opKind(const TcgV &Dst, const TcgV &Src) { + return (Dst.Kind =3D=3D IrPtr) ? Src.Kind : Dst.Kind; +} + +void TcgEmitter::genVecBinOpStr(StringRef Op, const TcgV &Dst, const TcgV = &Src0, + const TcgV &Src1) { + assertKinds({{Dst, IrPtr | IrPtrToOffset}, + {Src0, IrPtrToOffset}, + {Src1, IrPtrToOffset | IrValue | IrImmediate}}); + const VectorSize Size =3D Src0.vecSize(); + Out << "tcg_gen_gvec_" << Op << "(MO_" << (int)Size.ElementBitWidth <<= ", "; + emitArgListTcg({Dst, Src0, Src1}); + Out << ", " << Size.bytes() << ", " << Size.bytes() << ");\n"; + // Track number of vector operations + ++NumVectorInstructions; +} + +void TcgEmitter::genVecBinOp(const Instruction::BinaryOps Opcode, + const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1) { + genVecBinOpStr(mapVecBinOp(Opcode, Src0, Src1), Dst, Src0, Src1); +} + +void TcgEmitter::genVecSignedSatAdd(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1) { + genVecBinOpStr("ssadd", Dst, Src0, Src1); +} + +void TcgEmitter::genVecSignedSatSub(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1) { + genVecBinOpStr("sssub", Dst, Src0, Src1); +} + +void TcgEmitter::genVecUnsignedSatSub(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1) { + genVecBinOpStr("ussub", Dst, Src0, Src1); +} + +void TcgEmitter::genVecOrScalarBinOp(StringRef Op, const TcgV &Dst, + const TcgV &Src0, const TcgV &Src1) { + assertKinds({{Dst, IrValue | IrPtrToOffset}, + {Src0, IrValue | IrPtrToOffset | IrImmediate}, + {Src1, IrValue | IrPtrToOffset | IrImmediate}}); + switch (Dst.Kind) { + case IrValue: { + Out << "tcg_gen_" << Op << "_i" << Dst.tcgBitWidth() << "("; + emitArgListTcg({Dst, materialize(Src0), materialize(Src1)}); + Out << ");\n"; + } break; + case IrPtrToOffset: { + genVecBinOpStr(Op, Dst, Src0, Src1); + } break; + default: + abort(); + } +} + +void TcgEmitter::genVecSignedMax(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1) { + genVecOrScalarBinOp("smax", Dst, Src0, Src1); +} + +void TcgEmitter::genVecUnsignedMax(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1) { + genVecOrScalarBinOp("umax", Dst, Src0, Src1); +} + +void TcgEmitter::genVecSignedMin(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1) { + genVecOrScalarBinOp("smin", Dst, Src0, Src1); +} + +void TcgEmitter::genVecUnsignedMin(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1) { + genVecOrScalarBinOp("umin", Dst, Src0, Src1); +} + +void TcgEmitter::genVecMemcpy(const TcgV &Dst, const TcgV &Src, + const TcgV &Size) { + genVecUnaryCall("tcg_gen_gvec_mov", 8, Dst, Src, Size); +} + +void TcgEmitter::genVecMemset(const TcgV &Dst, const TcgV &Src, + const TcgV &Size) { + assertKinds({{Dst, IrPtrToOffset}, + {Src, IrValue | IrImmediate}, + {Size, IrImmediate}}); + switch (Src.Kind) { + case IrValue: + Out << "tcg_gen_gvec_dup_i" << Src.tcgBitWidth() << "(MO_" + << Src.llvmBitWidth() << ", "; + emitArgListTcg({Dst, Size, Size, Src}); + Out << ");\n"; + break; + case IrImmediate: + Out << "tcg_gen_gvec_dup_imm" << "(MO_" << Src.llvmBitWidth() << "= , "; + emitArgListTcg({Dst, Size, Size, Src}); + Out << ");\n"; + break; + default: + abort(); + } + // Track number of vector operations + ++NumVectorInstructions; +} + +void TcgEmitter::genVecSplat(const TcgV &Dst, const TcgV &Src) { + const size_t Bytes =3D Dst.vecSize().bytes(); + const auto Size =3D TcgV::makeImmediate(Twine(Bytes).str(), {T64, I64}= ); + genVecMemset(Dst, Src, Size); +} + +void TcgEmitter::genVecArrSplat(const TcgV &Dst, const TcgV &Src) { + assert(Src.ConstantExpression); + const VectorSize SrcSize =3D Src.vecSize(); + const VectorSize DstSize =3D Dst.vecSize(); + const std::string DstName =3D getName(Dst); + // NOTE: We are emitting static constant arrays of `uint64_t[]` with t= he + // purpose of initializing vectors to these constants using + // `tcg_gen_gvec_mov_var()`. This should be equivalent to a vectorize= d load + // from a constant pointer into the read-only section of the binary, i= nto a + // guest vector. If this is problematic we'll have + // resubprojects/helper-to-tcg/passes/backend/TcgEmit.hsort to adding + // constant vector storage to `env` if needed. + const std::string ArrData =3D Twine(DstName).concat("_data").str(); + Out << "static const " << C.intType(false, SrcSize.ElementBitWidth) <<= " " + << ArrData << "[] =3D " << getName(Src) << ";\n"; + Out << "tcg_gen_gvec_mov_var(MO_" << (int)SrcSize.ElementBitWidth << "= , " + << getName(getGlobalEnv()) << ", " << DstName << ", tcg_constant_p= tr(" + << ArrData << "), 0, " << SrcSize.bytes() << ", " << DstSize.bytes= () + << ");\n"; + // Track number of vector operations + ++NumVectorInstructions; +} + +void TcgEmitter::genVecBitsel(const TcgV &Dst, const TcgV &Cond, + const TcgV &Src0, const TcgV &Src1) { + assertKinds({{Dst, IrPtrToOffset}, + {Cond, IrPtrToOffset}, + {Src0, IrPtrToOffset}, + {Src1, IrPtrToOffset}}); + genVecCall("bitsel", {Dst, Cond, Src0, Src1}, Src0.vecSize(), + Src0.vecSize()); +} + +void TcgEmitter::genVecCmp(const TcgV &Dst, const CmpInst::Predicate &Pred, + const TcgV &Src0, const TcgV &Src1) { + assertKinds( + {{Dst, IrPtrToOffset}, {Src0, IrPtrToOffset}, {Src1, IrPtrToOffset= }}); + // NOTE: Return type of a LLVM vector compare is `<128 x i1>`, here the + // operand type is taken as the return type similar to how `icmp` is + // mapped. + const VectorSize Size =3D Src0.vecSize(); + Out << "tcg_gen_gvec_cmp(" << mapPredicate(Pred) << ", " << "MO_" + << (int)Size.ElementBitWidth << ", " << getName(Dst) << ", " + << getName(Src0) << ", " << getName(Src1) << ", " << Size.bytes() + << ", " << Size.bytes() << ");\n"; + // Track number of vector operations + ++NumVectorInstructions; +} + +void TcgEmitter::genAbs(const TcgV &Dst, const TcgV &Src) { + assertKinds( + {{Dst, IrValue | IrPtrToOffset}, {Src, IrValue | IrPtrToOffset}}); + switch (Dst.Kind) { + case IrValue: { + const auto FuncStr =3D + Twine("tcg_gen_abs_i").concat(Twine(Src.tcgBitWidth())).str(); + emitCallTcg(FuncStr, {Dst, Src}); + } break; + case IrPtrToOffset: { + genVecCall("abs", {Dst, Src}, Src.vecSize(), Dst.vecSize()); + } break; + default: + abort(); + } +} + +void TcgEmitter::genVecNot(const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrPtrToOffset}, {Src, IrPtrToOffset}}); + genVecCall("not", {Dst, Src}, Dst.vecSize(), Dst.vecSize()); +} + +void TcgEmitter::genVecSizeChange(StringRef Name, uint8_t DstElementBits, + const TcgV &Dst, const TcgV &Src) { + assertKinds({{Dst, IrPtrToOffset}, {Src, IrPtrToOffset}}); + const VectorSize Size =3D Src.vecSize(); + Out << "gen_vec_" << Name << "_" << (int)Size.ElementBitWidth << "_" + << (int)DstElementBits << "(" << getName(Dst) << ", " << getName(S= rc) + << ", " << Size.bytes() << ");\n"; + // Track number of vector operations + ++NumVectorInstructions; + // Indicates definitions of gen_helper_vec_[zext|trunc_sext] need to be + // emitted. + NeedVectorSizeChangeOps =3D true; +} + +void TcgEmitter::genVecTrunc(uint8_t DstElementBits, const TcgV &Dst, + const TcgV &Src) { + genVecSizeChange("trunc", DstElementBits, Dst, Src); +} + +void TcgEmitter::genVecSext(uint8_t DstElementBits, const TcgV &Dst, + const TcgV &Src) { + genVecSizeChange("sext", DstElementBits, Dst, Src); +} + +void TcgEmitter::genVecZext(uint8_t DstElementBits, const TcgV &Dst, + const TcgV &Src) { + genVecSizeChange("zext", DstElementBits, Dst, Src); +} + +static inline size_t roundToMultiple(size_t X, size_t Multiple) { + return Multiple * ((X + Multiple - 1) / Multiple); +} + +std::string CEmitter::intType(bool Signed, uint8_t LlvmSize) { + return Twine((Signed) ? "int" : "uint") + .concat(Twine(roundToMultiple(LlvmSize, 8))) + .concat("_t") + .str(); +} + +inline StringRef mapCPredicate(const CmpInst::Predicate &Pred) { + switch (Pred) { + case CmpInst::ICMP_EQ: + return "=3D=3D"; + case CmpInst::ICMP_NE: + return "!=3D"; + case CmpInst::ICMP_UGT: + return ">"; + case CmpInst::ICMP_UGE: + return ">=3D"; + case CmpInst::ICMP_ULT: + return "<"; + case CmpInst::ICMP_ULE: + return "<=3D"; + case CmpInst::ICMP_SGT: + return ">"; + case CmpInst::ICMP_SGE: + return ">=3D"; + case CmpInst::ICMP_SLT: + return "<"; + case CmpInst::ICMP_SLE: + return "<=3D"; + default: + abort(); + } +} + +inline bool predicateNeedsSignCast(const CmpInst::Predicate &Pred) { + switch (Pred) { + case CmpInst::ICMP_EQ: + case CmpInst::ICMP_NE: + case CmpInst::ICMP_UGT: + case CmpInst::ICMP_UGE: + case CmpInst::ICMP_ULT: + case CmpInst::ICMP_ULE: + return false; + case CmpInst::ICMP_SGT: + case CmpInst::ICMP_SGE: + case CmpInst::ICMP_SLT: + case CmpInst::ICMP_SLE: + return true; + default: + abort(); + } +} + +enum BinOpSrcCast { + CastNone, + CastSigned, + CastUnsigned, +}; + +std::string CEmitter::mapBinOp(const Instruction::BinaryOps &Opcode, + const TcgV &Src0, const TcgV &Src1) { + assert(Src0.Kind =3D=3D IrImmediate and Src1.Kind =3D=3D IrImmediate); + std::string Op; + BinOpSrcCast CastSrc0 =3D CastNone; + BinOpSrcCast CastSrc1 =3D CastNone; + switch (Opcode) { + case Instruction::Add: + Op =3D "+"; + break; + case Instruction::And: + Op =3D "&"; + break; + case Instruction::AShr: + CastSrc0 =3D CastSigned; + Op =3D ">>"; + break; + case Instruction::LShr: + CastSrc0 =3D CastUnsigned; + Op =3D ">>"; + break; + case Instruction::Shl: + Op =3D "<<"; + break; + case Instruction::Mul: + Op =3D "*"; + break; + case Instruction::UDiv: + CastSrc0 =3D CastUnsigned; + CastSrc1 =3D CastUnsigned; + Op =3D "/"; + break; + case Instruction::SDiv: + CastSrc0 =3D CastSigned; + CastSrc1 =3D CastSigned; + Op =3D "/"; + break; + case Instruction::Or: + Op =3D "|"; + break; + case Instruction::Sub: + Op =3D "-"; + break; + case Instruction::Xor: + Op =3D "^"; + break; + default: + abort(); + } + + std::string Expr =3D ""; + llvm::raw_string_ostream ExprStream(Expr); + ExprStream << "("; + if (CastSrc0 !=3D CastNone) { + ExprStream << "(" + << intType(CastSrc0 =3D=3D CastSigned, Src0.llvmBitWidt= h()) + << ") "; + } + ExprStream << getName(Src0) << " " << Op << " "; + if (CastSrc1 !=3D CastNone) { + ExprStream << "(" + << intType(CastSrc1 =3D=3D CastSigned, Src1.llvmBitWidt= h()) + << ") "; + } + ExprStream << getName(Src1) << ")"; + ExprStream.flush(); + + return Expr; +} + +// TODO: +TcgV CEmitter::ptrAdd(const TcgV &Ptr, const TcgV &Offset) { + assert(Offset.Kind =3D=3D IrImmediate); + switch (Ptr.Kind) { + case IrImmediate: { + std::string Expr =3D ""; + llvm::raw_string_ostream ExprStream(Expr); + ExprStream << "(" << intType(false, Ptr.tcgBitWidth()) + << " *) ((uintptr_t) " << getName(Ptr) << " + " + << getName(Offset) << ")"; + ExprStream.flush(); + return TcgV::makeImmediate(Expr, Ptr.intSize()); + }; + case IrPtrToOffset: { + std::string Expr =3D ""; + llvm::raw_string_ostream ExprStream(Expr); + ExprStream << "(" << getName(Ptr) << " + " << getName(Offset) << "= )"; + ExprStream.flush(); + TcgV Dst =3D Ptr; + Dst.Kind =3D IrPtrToOffset; + Dst.Name =3D Expr; + Dst.ConstantExpression =3D true; + return Dst; + }; + default: + abort(); + } +} + +TcgV CEmitter::ternary(const TcgV &Cond, const TcgV &True, const TcgV &Fal= se) { + assert(Cond.Kind =3D=3D IrImmediate); + std::string Expr =3D ""; + llvm::raw_string_ostream ExprStream(Expr); + ExprStream << "(" << getName(Cond) << " ? " << getName(True) << " : " + << getName(False) << ")"; + ExprStream.flush(); + return TcgV::makeConstantExpression(Expr, True.intSize(), True.Kind); +} + +TcgV CEmitter::deref(const TcgV &Ptr, ValueSize Size) { + assert(Ptr.Kind =3D=3D IrImmediate); + std::string Expr =3D Twine("*").concat(getName(Ptr)).str(); + return TcgV::makeImmediate(Expr, Size); +} + +TcgV CEmitter::compare(const CmpInst::Predicate &Pred, const TcgV &Lhs, + const TcgV &Rhs) { + assert(Lhs.Kind =3D=3D IrImmediate and Rhs.Kind =3D=3D IrImmediate); + const bool NeedsCast =3D predicateNeedsSignCast(Pred); + const std::string LhsCast =3D + (NeedsCast) ? "(" + intType(true, Lhs.llvmBitWidth()) + ")" : ""; + const std::string RhsCast =3D + (NeedsCast) ? "(" + intType(true, Rhs.llvmBitWidth()) + ")" : ""; + std::string Expr =3D ""; + llvm::raw_string_ostream ExprStream(Expr); + ExprStream << "(" << LhsCast << getName(Lhs) << " " << mapCPredicate(P= red) + << " " << RhsCast << getName(Rhs) << ")"; + ExprStream.flush(); + return TcgV::makeImmediate(Expr, Lhs.intSize()); +} + +TcgV CEmitter::extend(bool Signed, const TcgV &V, ValueSize Size) { + assert(V.Kind =3D=3D IrImmediate or + (V.ConstantExpression and V.Kind =3D=3D IrValue)); + std::string Expr =3D ""; + llvm::raw_string_ostream ExprStream(Expr); + ExprStream << "((" << intType(Signed, Size.LlvmBitWidth) << ") (" + << intType(Signed, V.llvmBitWidth()) << ") " << getName(V) + << ")"; + ExprStream.flush(); + return TcgV::makeImmediate(Expr, Size); +} + +TcgV CEmitter::binop(Instruction::BinaryOps Opcode, const TcgV &Src0, + const TcgV &Src1) { + std::string Op =3D mapBinOp(Opcode, Src0, Src1); + ValueSize LargestSize =3D (Src0.llvmBitWidth() > Src1.llvmBitWidth()) + ? Src0.intSize() + : Src1.intSize(); + return TcgV::makeImmediate(Op, LargestSize); +} + +void emitVectorMem(raw_ostream &Out) { + Out << "typedef struct VectorMem {\n"; + Out << " uint32_t allocated;\n"; + Out << "} VectorMem;\n\n"; + + Out << "static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size)\n= "; + Out << "{\n"; + Out << " uint32_t off =3D ROUND_UP(mem->allocated, size);\n"; + Out << " g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState,= " + << TempVectorBlock << "));\n"; + Out << " mem->allocated =3D off + size;\n"; + Out << " return offsetof(CPUArchState, " << TempVectorBlock + << ") + off;\n"; + Out << "}\n"; +} + +static void emitVectorSizeChangeHelper(raw_ostream &OutSource, + raw_ostream &OutHeader, StringRef N= ame, + StringRef IntPrefix, int SrcSize, + int DstSize) { + const std::string NameWithTypes =3D + (Twine("vec_") + Name + "_" + Twine(SrcSize) + "_" + Twine(DstSize= )) + .str(); + + // Emit helper declarations. + OutHeader << "DEF_HELPER_FLAGS_3(" << NameWithTypes + << ", TCG_CALL_NO_RWG, void, ptr, ptr, i32)\n"; + + // Emit helper definitions. + OutSource << "void HELPER(" << NameWithTypes + << ")(void *d, void *a, uint32_t size)\n{\n"; + OutSource << "for (intptr_t i =3D 0; i < (size / sizeof(" << IntPrefix + << SrcSize << "_t)); ++i) {\n"; + OutSource << IntPrefix << SrcSize << "_t aa =3D *((" << IntPrefix << S= rcSize + << "_t *) a + i);\n"; + OutSource << "*((" << IntPrefix << DstSize << "_t *) d + i) =3D aa;\n"; + OutSource << "}\n"; + OutSource << "}\n\n"; + + // Emit gen_vec_*() function invoking helper functions. + OutSource << "static inline void G_GNUC_UNUSED gen_" << NameWithTypes + << "(intptr_t dofs, intptr_t aofs, uint32_t size)\n{\n"; + OutSource << "TCGv_ptr d =3D tcg_temp_new_ptr();\n"; + OutSource << "TCGv_ptr a =3D tcg_temp_new_ptr();\n"; + OutSource << "tcg_gen_addi_ptr(d, tcg_env, dofs);\n"; + OutSource << "tcg_gen_addi_ptr(a, tcg_env, aofs);\n"; + OutSource << "gen_helper_" << NameWithTypes + << "(d, a, tcg_constant_i32(size));\n"; + OutSource << "}\n\n"; +} + +static void emitVectorIndex(raw_ostream &OutSource, const VectorLayout &VL, + size_t LaneSize) { + const size_t LanesPerColumn =3D 64 / LaneSize; + const size_t ColumnsPerBlock =3D VL.BlockBytes / 8; + OutSource << "inline size_t ind_" << LaneSize << "(size_t i) {\n"; + OutSource << "const size_t c =3D i / " << LanesPerColumn << ";\n"; + OutSource << "const size_t b =3D c / " << ColumnsPerBlock << ";\n"; + OutSource << "const size_t ci =3D i % " << LanesPerColumn << ";\n"; + OutSource << "const size_t bc =3D c % " << ColumnsPerBlock << ";\n"; + OutSource << "return " << (8 * VL.BlockBytes) / LaneSize << " * b"; + if (VL.HostBigEndian ^ (VL.Lane0 =3D=3D MostSignificant)) { + OutSource << " + " << LanesPerColumn << " * (" << ColumnsPerBlock = - 1 + << " - bc)"; + } else { + OutSource << " + " << LanesPerColumn << " * bc"; + } + if (VL.HostBigEndian ^ (VL.Lane0 =3D=3D MostSignificant)) { + OutSource << " + (" << LanesPerColumn - 1 << " - ci);\n"; + } else { + OutSource << " + ci;\n"; + } + OutSource << "}\n\n"; +} + +void emitVectorSizeChangeOps(raw_ostream &OutSource, raw_ostream &OutHeade= r, + const VectorLayout &VL) { + OutSource << "#define HELPER_H \"helper-to-tcg-support-helpers.h\"\n"; + OutSource << "#include \"exec/helper-proto-common.h\"\n"; + OutSource << "#include \"exec/helper-proto.h.inc\"\n"; + OutSource << "#include \"exec/helper-gen-common.h\"\n"; + OutSource << "#include \"exec/helper-gen.h.inc\"\n\n"; + + const uint8_t Sizes[] =3D {8, 16, 32, 64}; + + for (uint8_t Size : Sizes) { + emitVectorIndex(OutSource, VL, Size); + } + + for (uint8_t SmallSize : Sizes) { + for (uint8_t LargeSize : Sizes) { + if (SmallSize >=3D LargeSize) { + continue; + } + emitVectorSizeChangeHelper(OutSource, OutHeader, "trunc", "uin= t", + LargeSize, SmallSize); + emitVectorSizeChangeHelper(OutSource, OutHeader, "zext", "uint= ", + SmallSize, LargeSize); + emitVectorSizeChangeHelper(OutSource, OutHeader, "sext", "int", + SmallSize, LargeSize); + } + } +} + +void emitHelperGen(raw_ostream &Out, StringRef Name, Type *ReturnTy, + ArrayRef ArgTys) { + // Given LLVM Type produce the corresponding TCG type that would be ex= pected + // as a helper argument. + auto emitType =3D [&](Type *Ty) { + switch (Ty->getTypeID()) { + case Type::IntegerTyID: { + auto IntTy =3D cast(Ty); + auto Size =3D ValueSize::fromLlvmType(IntTy); + assert(Size); + Out << "TCGv_i" << (int)Size->TcgBitWidth; + return true; + } + case Type::PointerTyID: { + Out << "TCGv_ptr"; + return true; + } + default: + return false; + }; + }; + + // Given LLVM Type and name string produce the neccessary `TCGv` to + // `TCGTemp` conversion expeted by `tcg_gen_callN`. + auto emitTemp =3D [&](Type *Ty, StringRef str) { + switch (Ty->getTypeID()) { + case Type::IntegerTyID: { + auto IntTy =3D cast(Ty); + auto Size =3D ValueSize::fromLlvmType(IntTy); + assert(Size); + Out << "tcgv_i" << (int)Size->TcgBitWidth << "_temp(" << str <= < ")"; + } break; + case Type::PointerTyID: { + Out << "tcgv_ptr_temp(" << str << ")"; + } break; + default: + Out << "NULL"; + break; + }; + }; + + Out << "extern TCGHelperInfo helper_info_" << Name << ";\n"; + Out << "static inline void gen_helper_" << Name << "("; + + bool HasRet =3D emitType(ReturnTy); + if (HasRet) { + Out << " ret"; + } + for (int i =3D 0; i < ArgTys.size(); ++i) { + if (HasRet or i > 0) { + Out << ", "; + } + assert(emitType(ArgTys[i])); + Out << " a" << i; + } + Out << ")\n{\n"; + + Out << "tcg_gen_call" << ArgTys.size() << "(helper_info_" << Name << "= .func" + << ", &helper_info_" << Name << ", "; + + emitTemp(ReturnTy, "ret"); + for (int i =3D 0; i < ArgTys.size(); ++i) { + Out << ", "; + emitTemp(ArgTys[i], Twine("a").concat(Twine(i)).str()); + } + Out << ");\n"; + Out << "}\n"; +} diff --git a/subprojects/helper-to-tcg/src/TcgGenPass/TcgEmit.hpp b/subproj= ects/helper-to-tcg/src/TcgGenPass/TcgEmit.hpp new file mode 100644 index 0000000000..26d0ba2afe --- /dev/null +++ b/subprojects/helper-to-tcg/src/TcgGenPass/TcgEmit.hpp @@ -0,0 +1,315 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#pragma once + +#include "TcgType.hpp" + +#include +#include +#include // for CmpInst::Predicate +#include +#include +#include + +#include + +using llvm::CmpInst; +using llvm::Instruction; +using llvm::raw_ostream; +using llvm::SmallVector; +using llvm::StringRef; +using llvm::Twine; +using llvm::Type; +using llvm::Value; + +class CEmitter; + +struct VectorLayout; + +inline std::string getName(const TcgV &V) { + if (!V.Name.empty() or V.ConstantExpression) { + return V.Name; + } else { + switch (V.Kind) { + case IrImmediate: + return (!V.Name.empty()) ? V.Name + : Twine("imm").concat(Twine(V.Id)).st= r(); + case IrValue: + return Twine("tmp").concat(Twine(V.Id)).str(); + case IrPtr: + return Twine("ptr").concat(Twine(V.Id)).str(); + case IrPtrToOffset: + return Twine("vec").concat(Twine(V.Id)).str(); + case IrLabel: + return Twine("label").concat(Twine(V.Id)).str(); + default: + abort(); + }; + } +} + +// Small helper class to construct `Twine`s on the stack. +template class StackTwine { + llvm::SmallString Str; + + public: + StackTwine() =3D delete; + StackTwine(Twine &&T) { T.toVector(Str); } + operator StringRef() { return Str; } +}; + +class TcgEmitter { + raw_ostream &Out; + CEmitter &C; + size_t AllocatedVectorMemory =3D 0; + size_t NumVectorInstructions =3D 0; + bool EmittedVectorMem =3D false; + + void genVecUnaryCall(StringRef Name, int ElementSize, const TcgV &Dst, + const TcgV &Src, const TcgV &Size); + void genVecBinaryCall(StringRef Name, int ElementSize, const TcgV &Dst, + const TcgV &Src0, const TcgV &Src1, size_t Size); + void genVecCall(StringRef Name, llvm::ArrayRef Args, + const VectorSize OpSize, const VectorSize MaxSize); + void genVecSizeChange(StringRef Name, uint8_t DstElementBits, + const TcgV &Dst, const TcgV &Src); + + public: + bool NeedVectorSizeChangeOps =3D false; + + TcgEmitter(raw_ostream &Out, CEmitter &C) : Out(Out), C(C) {} + + inline size_t allocatedVectorMemory() const { + return AllocatedVectorMemory; + } + inline size_t numVectorInstructions() const { + return NumVectorInstructions; + } + + const TcgV getGlobalEnv() { + return TcgV::makeConstantExpression("tcg_env", {}, IrPtr); + } + + const TcgV getDisasContext() { + return TcgV::makeConstantExpression("ctx", {}, IrPtr); + } + + // String representation of types + const std::string getType(const TcgV &Value); + + inline const TcgV materialize(const TcgV &Value) { + if (Value.Kind !=3D IrImmediate) { + return Value; + } + TcgV M =3D Value; + M.Name =3D Twine("tcg_constant_i") + .concat(Twine((int)Value.tcgBitWidth())) + .concat("(") + .concat(getName(Value)) + .concat(")") + .str(); + M.Kind =3D IrValue; + return M; + } + + template void emitArgListTcg(const I Beg, const I End) { + auto It =3D Beg; + if (It !=3D End) { + Out << getName(*It); + ++It; + } + while (It !=3D End) { + Out << ", " << getName(*It); + ++It; + } + } + + template + void emitCall(const StringRef S, const I Beg, const I End) { + Out << S << '('; + auto It =3D Beg; + if (It !=3D End) { + Out << *It; + ++It; + } + while (It !=3D End) { + Out << ", " << *It; + ++It; + } + Out << ");\n"; + } + + template + void emitCallTcg(const StringRef S, Iterator Begin, Iterator End) { + assert(Begin !=3D End); + Out << S << '('; + Out << getName(*Begin); + ++Begin; + while (Begin !=3D End) { + Out << ", " << getName(*Begin); + ++Begin; + } + Out << ");\n"; + } + + inline void emitArgListTcg(const std::initializer_list Args) { + emitArgListTcg(Args.begin(), Args.end()); + } + + inline void emitCall(const StringRef S, + const std::initializer_list Args) { + emitCall(S, Args.begin(), Args.end()); + } + + inline void emitCallTcg(StringRef S, std::initializer_list Args)= { + emitCallTcg(S, Args.begin(), Args.end()); + } + + inline void genCallHelper(const StringRef Helper, + const std::initializer_list Args) { + auto Func =3D Twine("gen_").concat(Helper).str(); + emitCallTcg(Func, Args); + } + + template + void genCallHelper(const StringRef Helper, I Beg, I End) { + auto Func =3D Twine("gen_").concat(Helper).str(); + emitCallTcg(Func, Beg, End); + } + + template + void genCallCFunc(const StringRef Name, TcgV Ret, I Beg, I End) { + if (Ret.Kind !=3D IrInvalid) { + Out << getName(Ret) << " =3D "; + } + emitCallTcg(Name, Beg, End); + } + + void genNewLabel(); + void genSetLabel(const TcgV &L); + + void defineNewTemp(const TcgV &Tcg); + + void genBr(const TcgV &L); + + void genExts(const TcgV &Dst, const TcgV &Src); + void genExtI32I64(const TcgV &Dst, const TcgV &Src); + void genExtrlI64I32(const TcgV &Dst, const TcgV &Src); + void genExtuI32I64(const TcgV &Dst, const TcgV &Src); + void genExtrhI64I32(const TcgV &Dst, const TcgV &Src); + void genExtract(bool Sign, const TcgV &Dst, const TcgV &Src, + const TcgV &Offset, const TcgV &Length); + void genDeposit(const TcgV &Dst, const TcgV &Into, const TcgV &From, + const TcgV &Offset, const TcgV &Length); + + void genPtrToValue(const TcgV &Dst, const TcgV &Src); + void genValueToPtr(const TcgV &Dst, const TcgV &Src); + + void genConcat(const TcgV &Dst, const TcgV &Src1, const TcgV &Src2); + void genMov(const TcgV &Dst, const TcgV &Src); + void genMovPtr(const TcgV &Dst, const TcgV &Src); + void genAddPtr(const TcgV &Dst, const TcgV &Ptr, const TcgV &Offset); + void genBinOp(const TcgV &Dst, const Instruction::BinaryOps Opcode, + const TcgV &Src0, const TcgV &Src1); + void genMovcond(const CmpInst::Predicate &Pred, const TcgV &Ret, + const TcgV &C1, const TcgV &C2, const TcgV &V1, + const TcgV &V2); + void genSetcond(const CmpInst::Predicate &Pred, const TcgV &Dst, + const TcgV &Op1, const TcgV &Op2); + void genBrcond(const CmpInst::Predicate &Pred, const TcgV &Arg1, + const TcgV &Arg2, const TcgV &Label); + + std::string getMemOp(uint8_t Size, uint8_t Endianness, uint8_t Sign); + void genGuestLoad(const TcgV &Dst, const TcgV &Ptr, StringRef MemOp); + void genGuestStore(const TcgV &Ptr, const TcgV &Src, StringRef MemOp); + void genHostLoad(const TcgV &Dst, const TcgV &Ptr, const TcgV &Offset); + void genHostLoadFromVec(const TcgV &Dst, const TcgV &Offset); + void genHostStore(const TcgV &Ptr, const TcgV &Src); + + void genFunnelShl(const TcgV &Dst, const TcgV &Src0, const TcgV &Src1, + const TcgV &Shift); + void genBitreverse(const TcgV &Dst, const TcgV &Src); + void genAbs(const TcgV &Dst, const TcgV &Src); + void genCountLeadingZeros(const TcgV &Dst, const TcgV &Src); + void genCountTrailingZeros(const TcgV &Dst, const TcgV &Src); + void genCountOnes(const TcgV &Dst, const TcgV &Src); + void genByteswap(const TcgV &Dst, const TcgV &Src); + void genUnsignedSatSub(const TcgV &Dst, const TcgV &Src0, const TcgV &= Src1); + + // Vector ops. + void genVecBinOpStr(StringRef Op, const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1); + void genVecBinOp(const Instruction::BinaryOps Opcode, const TcgV &Dst, + const TcgV &Src0, const TcgV &Src1); + void genVecOrScalarBinOp(StringRef Op, const TcgV &Dst, const TcgV &Sr= c0, + const TcgV &Src1); + void genVecSignedSatAdd(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1); + void genVecSignedSatSub(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1); + void genVecUnsignedSatSub(const TcgV &Dst, const TcgV &Src0, + const TcgV &Src1); + void genVecSignedMax(const TcgV &Dst, const TcgV &Src0, const TcgV &Sr= c1); + void genVecUnsignedMax(const TcgV &Dst, const TcgV &Src0, const TcgV &= Src1); + void genVecSignedMin(const TcgV &Dst, const TcgV &Src0, const TcgV &Sr= c1); + void genVecUnsignedMin(const TcgV &Dst, const TcgV &Src0, const TcgV &= Src1); + void genVecMemcpy(const TcgV &Dst, const TcgV &Src, const TcgV &Size); + void genVecMemset(const TcgV &Dst, const TcgV &Src, const TcgV &Size); + void genVecSplat(const TcgV &Dst, const TcgV &Src); + void genVecArrSplat(const TcgV &Dst, const TcgV &Src); + void genVecBitsel(const TcgV &Dst, const TcgV &Cond, const TcgV &Src0, + const TcgV &Src1); + void genVecCmp(const TcgV &Dst, const CmpInst::Predicate &Pred, + const TcgV &Src0, const TcgV &Src1); + void genVecNot(const TcgV &Dst, const TcgV &Src); + void genVecTrunc(uint8_t DstElementBits, const TcgV &Dst, const TcgV &= Src); + void genVecSext(uint8_t DstElementBits, const TcgV &Dst, const TcgV &S= rc); + void genVecZext(uint8_t DstElementBits, const TcgV &Dst, const TcgV &S= rc); +}; + +class CEmitter { + std::string mapBinOp(const Instruction::BinaryOps &Opcode, const TcgV = &Src0, + const TcgV &Src1); + + public: + CEmitter() {} + + std::string intType(bool Signed, uint8_t LlvmSize); + TcgV ptrAdd(const TcgV &Ptr, const TcgV &Offset); + TcgV ternary(const TcgV &Cond, const TcgV &True, const TcgV &False); + TcgV deref(const TcgV &Ptr, ValueSize Size); + TcgV compare(const CmpInst::Predicate &Pred, const TcgV &Src0, + const TcgV &Src1); + TcgV extend(bool Signed, const TcgV &V, ValueSize Size); + TcgV binop(Instruction::BinaryOps Opcode, const TcgV &Src0, + const TcgV &Src1); +}; + +// The below function deal with a lot of code generation that we expect to= be +// present in the output. + +// Emits `VectorMem` struct definition along with allocation funcs needed = for +// producing vector temporaries. +void emitVectorMem(raw_ostream &Out); +// Emit `gen_vec_zext*()` and friends for performing vector size changing +// operations, taking target vector layout into account. +void emitVectorSizeChangeOps(raw_ostream &OutSource, raw_ostream &OutHeade= r, + const VectorLayout &VL); +// Emits gen_helper_*() definition for helpers that failed to translate. +void emitHelperGen(raw_ostream &Out, StringRef Name, Type *ReturnTy, + llvm::ArrayRef ArgTys); --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381038; cv=none; d=zohomail.com; s=zohoarc; b=AaUQKKD5Aw/wgVnGW716StY0mDk7sSCDbfIN7trveOKOK5grLv3wUT0WsSQTTEdv0pQSBWf0OAvt4mwtZ98Cb5qpEtBQVVFw2qlwms+LK+lkSadmLznBpgc/pmQa0gN6xX3UfCKX9aFdpFIQSycvKJxi4RyZPRWkPKamprL3k7c= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381038; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=y7kRYOQZQnffNVG0Mg/57xQtZe9BL/W/UU2IwzeD6JQ=; b=VPeLMqXYwXO1yIKhoPjet3fGeuGjG36Ov6o3I66VfAVYf0Qm3XPFqEn9APYf4sthF2/e2PVUec0/3CymP5auWQxjM1VuhAHvVvKj6t01ga9RH8nBmHMHkWjeQMRb8x8fqkIs6Xb362mSboT6Lr92FpmPq5hPSdMflAud5RPJDlQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381038075979.6307245412916; Wed, 29 Jul 2026 20:10:38 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7H-0004es-Lv; Wed, 29 Jul 2026 23:07:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH74-0004Qq-C4 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:15 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH6z-0002yV-Q4 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=y7kRYOQZQnffNVG0Mg/57xQtZe9BL/W/UU2IwzeD6JQ=; b=QsMgZYfrTLRDoNc HjCkNpvPJq2oB8ZCxv+AFhAHV425dXVMvhd1YZrDMXp0parq26CPmSH+9QtAWHUgxF5bgH2Sd6YEm QkWaCZ06EGRSDs18LHuiaweSEVKFv1YWqumtIiajf84gVyUiIsHaAH4U+R4WMfO63lx80A5iz70C6 oY=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 34/50] helper-to-tcg: TcgGenPass, map arguments to TCG Date: Thu, 30 Jul 2026 05:10:08 +0200 Message-ID: <20260730031025.12926-35-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381039729158500 Content-Type: text/plain; charset="utf-8" Mapping for arguments is slighty different than other `Value`s and depend on function annotations, perform it as a separe pass. Signed-off-by: Anton Johansson --- subprojects/helper-to-tcg/meson.build | 1 + .../src/TcgGenPass/MapArguments.cpp | 122 ++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 subprojects/helper-to-tcg/src/TcgGenPass/MapArguments.c= pp diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index c03a4d5df6..22190025d0 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -51,6 +51,7 @@ sources =3D [ 'src/TcgGenPass/TcgGenPass.cpp', 'src/TcgGenPass/LinearizeBlocks.cpp', 'src/TcgGenPass/TcgEmit.cpp', + 'src/TcgGenPass/MapArguments.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/TcgGenPass/MapArguments.cpp b/su= bprojects/helper-to-tcg/src/TcgGenPass/MapArguments.cpp new file mode 100644 index 0000000000..04aa8cf10c --- /dev/null +++ b/subprojects/helper-to-tcg/src/TcgGenPass/MapArguments.cpp @@ -0,0 +1,122 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "DebugInfo.hpp" +#include "ValueMapping.hpp" + +#include "Error.hpp" +#include "FunctionAnnotation.hpp" +#include "TcgType.hpp" + +#include +#include +#include +#include + +#define DEBUG_TYPE "map-arguments" + +// +// Map Arguments +// +// Assign `TcgV`s to function arguments, taking function annotations into +// account to force types. Mapping them early and separately both makes s= ure +// that no other pass accidently assign to them, and separates out any spe= cial +// case logic that's necessary. +// + +using namespace llvm; + +static Expected mapIntegerArgument(TempAllocationData &TAD, + const DebugInfoMapTy &DebugInfo, + const Argument *Arg, + uint8_t Annotations) { + auto *IntTy =3D cast(Arg->getType()); + auto Size =3D ValueSize::fromLlvmType(IntTy); + if (!Size) { + return Size.takeError(); + } + + StringRef Name =3D getDebugVarName(DebugInfo, Arg); + + if ((Annotations & (uint8_t)ArgumentAnnotation::Immediate) !=3D 0) { + auto Tcg =3D TcgV::makeImmediate(Name, *Size); + return TAD.map(Arg, Tcg); + } else { + auto Tcg =3D TcgV::makeTemp(*Size, IrValue); + Tcg.Name =3D Name; + return TAD.map(Arg, Tcg); + } +} + +static Expected mapPointerArgument(TempAllocationData &TAD, + const DebugInfoMapTy &DebugInfo, + const Argument *Arg, + uint8_t Annotations) { + // If the value has an associated name from the debug information, use= it + StringRef Name{}; + if (auto It =3D DebugInfo.find(Arg); It !=3D DebugInfo.end()) { + Name =3D It->second.VarName; + } + + if ((Annotations & (uint8_t)ArgumentAnnotation::PtrToOffset) !=3D 0) { + auto Tcg =3D TcgV::makeVector({}); + Tcg.Name =3D Name; + return TAD.map(Arg, Tcg); + } else { + auto Tcg =3D TcgV::makeTemp({}, IrPtr); + Tcg.Name =3D Name; + return TAD.map(Arg, Tcg); + } +} + +static Expected mapArgument(TempAllocationData &Data, + const DebugInfoMapTy &DebugInfo, + const Argument *Arg, uint8_t Annotations= ) { + // We only map each argument once, assert it's not been mapped previou= sly. + assert(!Data.Map.count(Arg)); + + Type *Ty =3D Arg->getType(); + if (isa(Ty)) { + return mapIntegerArgument(Data, DebugInfo, Arg, Annotations); + } else if (isa(Ty)) { + return mapPointerArgument(Data, DebugInfo, Arg, Annotations); + } + + return mkError("Unable to map value ", Arg); +} + +Error mapArguments(const llvm::Function &F, + const AnnotationMapTy &AnnotationMap, + const DebugInfoMapTy &DebugInfo, TempAllocationData &Da= ta) { + // Map arguments + for (size_t I =3D 0; I < F.arg_size(); ++I) { + const Argument *Arg =3D F.getArg(I); + auto It =3D AnnotationMap.find(&F); + const uint8_t Annotations =3D + (It !=3D AnnotationMap.end()) ? It->second.getArgFlag(I) : 0; + Expected TcgArg =3D mapArgument(Data, DebugInfo, Arg, Annota= tions); + if (!TcgArg) { + return TcgArg.takeError(); + } + LLVM_DEBUG({ + dbgs() << "Mapped argument " << *Arg << " to: \n"; + TcgArg->dump(dbgs()); + }); + } + + return Error::success(); +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381156; cv=none; d=zohomail.com; s=zohoarc; b=Wdj3BTAwZl1N0o2nqW8rKWoNQ2XVhqrC4q0iJJDtBt+gjfjMaCY4WBNIMxwTjVAo1EG0Lq6uReQJmrWVsllLmrjKEEXxOex3Jz/lElPAKCbgJFxP+XFzhkGWqYlc0v5YqeeyqXPP2GF8p9t41nbANXuh4cXTrFgVyf++7GmLRz4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381156; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=bLMxEDtYtHEQEK6wR7TDb5jQ5+u/BTLS7BKnJclrKiw=; b=SpA1HXONDxo2lJ5AhgLMsgF6gR0f85oSfoZvccR5ctyCkI6fbY11EFe5E2+fyDtC1q6SUuYpVJit7I8qrQx/GyxUSrzH30TM/N6RbikW1WJ7IL6MyDvinXZ8LqQ9Kr+Nb4Aa6cGwZ8t0LlGr38PjIeEIMIAhM/d9JqOhT4coAV8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381156244314.3104041832131; Wed, 29 Jul 2026 20:12:36 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7a-0004zP-Qz; Wed, 29 Jul 2026 23:07:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH76-0004Sr-DQ for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:18 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH72-0002zK-W1 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:16 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=bLMxEDtYtHEQEK6wR7TDb5jQ5+u/BTLS7BKnJclrKiw=; b=XvKmkQwS5YWCu3v OsNFjGfbltcq1N+S8SpStFyVUiRg4+txiPz5LfTgvmVqw8FJImVEzEMgHyTqR2VEtI+022f8FKq/Q DR6ViXNAxVAS9lOwE4Uj3iS7MygyKX1LIIkvweq01N35ytl9EN2v8pKylZxXGpfUUiNO7Gkn81uCe Pc=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 35/50] helper-to-tcg: TcgGenPass, propagate constant expresssions Date: Thu, 30 Jul 2026 05:10:09 +0200 Message-ID: <20260730031025.12926-36-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381158243158500 Content-Type: text/plain; charset="utf-8" In a forward pass over the instructions, fold and propagate constant expressions to `TcgV`s with a string representing the expression. This needs to be performed before register allocation where `TcgV` registers are assigned to `Value`s to get the best register reuse. Register allocation is also performed in a backwards pass over the instructions, so these two passes cannot be nicely combined. Signed-off-by: Anton Johansson --- subprojects/helper-to-tcg/meson.build | 1 + .../src/TcgGenPass/MapConstantExpressions.cpp | 328 ++++++++++++++++++ 2 files changed, 329 insertions(+) create mode 100644 subprojects/helper-to-tcg/src/TcgGenPass/MapConstantExp= ressions.cpp diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 22190025d0..046cdb916b 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -52,6 +52,7 @@ sources =3D [ 'src/TcgGenPass/LinearizeBlocks.cpp', 'src/TcgGenPass/TcgEmit.cpp', 'src/TcgGenPass/MapArguments.cpp', + 'src/TcgGenPass/MapConstantExpressions.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/TcgGenPass/MapConstantExpression= s.cpp b/subprojects/helper-to-tcg/src/TcgGenPass/MapConstantExpressions.cpp new file mode 100644 index 0000000000..0d0810ebc8 --- /dev/null +++ b/subprojects/helper-to-tcg/src/TcgGenPass/MapConstantExpressions.cpp @@ -0,0 +1,328 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "ValueMapping.hpp" + +#include "DebugInfo.hpp" +#include "Error.hpp" +#include "PseudoInst.hpp" +#include "TcgEmit.hpp" +#include "TcgGlobalMap.hpp" +#include "TcgType.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +// +// Functions for mapping an LLVM Value to a TcgV +// + +// Provides a C string representation of a ConstantInt +static std::string constantIntToStr(const ConstantInt *C) { + SmallString<20> ResultStr; + auto *Int =3D cast(C); + const APInt Value =3D Int->getUniqueInteger(); + const unsigned BitWidth =3D Int->getBitWidth(); + if (BitWidth =3D=3D 1) { + // Emit as bool + return (Value.getBoolValue()) ? "true" : "false"; + } else if (BitWidth =3D=3D 64 and !Int->isNegative() and Int->uge(0xef= ff)) { + // Emit hex-formatted integer as 64-bit constants often occur in v= ector + // expressions, and are way easier to read. + Value.toString(ResultStr, 16, false, true); + return Twine(ResultStr).str(); + } else { + // Emit as signed integer + const char *SuffixStr =3D ""; + if (Value.ugt(UINT32_MAX) or C->getBitWidth() =3D=3D 64) { + SuffixStr =3D Int->isNegative() ? "ll" : "ull"; + } + bool IsMax =3D + (Int->isNegative()) ? Value.isMaxSignedValue() : Value.isMaxVa= lue(); + bool IsMin =3D Int->isNegative() and Value.isMinSignedValue(); + unsigned Bitwidth =3D Value.getBitWidth(); + if (IsMax) { + return Twine("INT").concat(Twine(Bitwidth)).concat("_MAX").str= (); + } else if (IsMin) { + return Twine("INT").concat(Twine(Bitwidth)).concat("_MIN").str= (); + } else { + Value.toString(ResultStr, 10, Value.isNegative(), true); + return Twine(ResultStr).concat(SuffixStr).str(); + } + } +} + +static Expected mapIntegerConstant(TempAllocationData &TAD, + const ConstantInt *V) { + auto Size =3D ValueSize::fromLlvmType(cast(V->getType())); + if (!Size) { + return Size.takeError(); + } + auto Tcg =3D TcgV::makeTemp(*Size, IrImmediate); + Tcg.Name =3D constantIntToStr(V); + return TAD.map(V, Tcg); +} + +static Expected mapVectorConstant(TempAllocationData &TAD, + const AnnotationMapTy &Annotations, + const DebugInfoMapTy &DebugInfo, + const Value *V, VectorType *VecTy)= { + auto *Const =3D dyn_cast(V); + if (!Const) { + return mkError("Non-constant vector"); + } + + auto Size =3D VectorSize::fromLlvmType(VecTy); + if (!Size) { + return Size.takeError(); + } + auto Tcg =3D TcgV::makeVector(*Size); + + // At this point, splatted vectors should have been converted to calls= to + // @VecSplat, to more closely match TCG and benefit from future variab= le + // assignments. + assert(!Const->getSplatValue()); + + std::string ExprStr; + raw_string_ostream Expr(ExprStr); + + // Map constant elements of vector where elements differ + // <32 x i32> + + Expr << "{"; + for (unsigned I =3D 0; I < Size->ElementCount; ++I) { + ConstantInt *C =3D cast(Const->getAggregateElement(I)= ); + Expr << constantIntToStr(C); + if (I < Size->ElementCount - 1) { + Expr << ", "; + } + } + Expr << "}"; + Tcg.Name =3D ExprStr; + Tcg.ConstantExpression =3D true; + + return TAD.map(V, Tcg); +} + +// Given a LLVM value, assigns a TcgV by type (integer, pointer, vector). = If +// the given value has already been mapped to a TcgV, return it. +static Expected mapConstant(TempAllocationData &TAD, + const AnnotationMapTy &AnnotationMap, + const DebugInfoMapTy &DebugInfo, + const Value *V) { + // Return previously mapped value + auto It =3D TAD.Map.find(V); + if (It !=3D TAD.Map.end()) { + return It->second; + } + + Type *Ty =3D V->getType(); + if (auto *ConstInt =3D dyn_cast(V)) { + return mapIntegerConstant(TAD, ConstInt); + } else if (isa(Ty)) { + return mapVectorConstant(TAD, AnnotationMap, DebugInfo, V, + cast(Ty)); + } + + return mkError("Unable to map value ", V); +} + +Error propagateConstantExpressions(CEmitter &C, const Function &F, + const LinearBlocks &Blocks, + const AnnotationMapTy &AnnotationMap, + const DebugInfoMapTy &DebugInfo, + const TcgGlobalMap &TcgGlobals, + TempAllocationData &TAD) { + SmallVector Worklist; + for (BasicBlock *BB : Blocks) { + for (Instruction &I : *BB) { + // Skip all instructions for which all operands have not been + // mapped, at this point we're only mapping constant expressio= ns, so + // this is equivalent to all operands being constant expressio= ns. + bool SkipInstruction =3D false; + SmallVector Ops; + for (Value *V : getOperands(&I)) { + // Try and map `V` as a constant, or return previously map= ped + // value. At this point any previously mapped value must b= e an + // argument to the function. + Expected T =3D + mapConstant(TAD, AnnotationMap, DebugInfo, V); + if (!T or T->Kind =3D=3D IrValue or T->Kind =3D=3D IrPtr) { + // Do break out here, we still need to map all operand= s, + // consider + // + // call @func(i32 %nonconst, i32 0). + SkipInstruction =3D true; + continue; + } + Ops.push_back(*T); + } + if (SkipInstruction) { + continue; + } + + switch (I.getOpcode()) { + case Instruction::SExt: + case Instruction::ZExt: { + auto *IntTy =3D dyn_cast(I.getType()); + if (!IntTy) { + continue; + } + auto Size =3D ValueSize::fromLlvmType(IntTy); + if (!Size) { + return Size.takeError(); + } + bool Signed =3D (I.getOpcode() =3D=3D Instruction::SExt); + TAD.Map[&I] =3D C.extend(Signed, Ops[0], *Size); + } break; + case Instruction::Trunc: { + auto Trunc =3D cast(&I); + if (!Trunc->getDestTy()->isIntegerTy()) { + continue; + } + TAD.Map[&I] =3D Ops[0]; + } break; + case Instruction::Add: + case Instruction::And: + case Instruction::AShr: + case Instruction::LShr: + case Instruction::Mul: + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::Or: + case Instruction::Shl: + case Instruction::Sub: + case Instruction::Xor: { + auto Bin =3D cast(&I); + if (!isa(Bin->getType())) { + continue; + } + assert(Ops[0].Kind =3D=3D Ops[1].Kind); + TAD.Map[&I] =3D C.binop(Bin->getOpcode(), Ops[0], Ops[1]); + } break; + case Instruction::ICmp: { + auto *ICmp =3D cast(&I); + assert(Ops[0].Kind =3D=3D Ops[1].Kind); + TAD.Map[&I] =3D C.compare(ICmp->getPredicate(), Ops[0], Op= s[1]); + } break; + case Instruction::Call: { + auto *Call =3D cast(&I); + + // Rule out calls which are marked as returning integer + // immediates first, then handle specific pseudo instructi= ons. + + Type *RetTy =3D Call->getType(); + + if (auto IntTy =3D dyn_cast(RetTy)) { + auto It =3D AnnotationMap.find(Call->getCalledFunction= ()); + if (It !=3D AnnotationMap.end() and + It->second.isSet( + FunctionAnnotation::ReturnsImmediate)) { + auto Size =3D ValueSize::fromLlvmType(IntTy); + if (!Size) { + return Size.takeError(); + } + auto Tcg =3D TcgV::makeTemp(*Size, IrImmediate); + Tcg.Name =3D getDebugVarName(DebugInfo, Call); + Tcg.Kind =3D IrImmediate; + TAD.Map[Call] =3D Tcg; + continue; + } + } + + switch (getPseudoInstFromCall(Call)) { + case IdentityMap: { + TcgV Tcg; + if (auto *IntTy =3D dyn_cast(RetTy)) { + auto Size =3D ValueSize::fromLlvmType(IntTy); + if (!Size) { + return Size.takeError(); + } + Tcg =3D TcgV::makeTemp(*Size, IrValue); + } else if (auto *VecTy =3D dyn_cast(RetTy)= ) { + auto Size =3D VectorSize::fromLlvmType(VecTy); + if (!Size) { + return Size.takeError(); + } + Tcg =3D TcgV::makeVector(*Size); + } else { + abort(); + } + Tcg.ConstantExpression =3D true; + Tcg.Name =3D Ops[0].Name; + TAD.Map[&I] =3D Tcg; + } break; + case PtrAdd: { + TAD.Map[&I] =3D C.ptrAdd(Ops[0], Ops[1]); + } break; + case Movcond: { + auto LlvmPred =3D static_cast( + cast(Call->getOperand(0))->getZExtVal= ue()); + const TcgV Cond =3D C.compare(LlvmPred, Ops[1], Ops[2]= ); + TAD.Map[&I] =3D C.ternary(Cond, Ops[3], Ops[4]); + } break; + case AccessGlobalArray: { + const uint64_t TypeIndex =3D + cast(Call->getArgOperand(0)) + ->getZExtValue(); + const uint64_t Offset =3D + cast(Call->getArgOperand(1)) + ->getZExtValue(); + assert(TypeIndex < TcgGlobals.size()); + auto It =3D TcgGlobals[TypeIndex].find(Offset); + assert(It !=3D TcgGlobals[TypeIndex].end()); + const TcgGlobal Global =3D It->second; + if (Ops[2].Kind !=3D IrImmediate) { + return mkError( + "Global array access with non-immediate index"= ); + } + auto Code =3D Global.Code.str() + "[" + getName(Ops[2]= ) + "]"; + TAD.Map[&I] =3D TcgV::makeConstantExpression( + Code, *ValueSize::fromBitWidth(Global.Size), IrVal= ue); + } break; + case AccessGlobalValue: { + const uint64_t TypeIndex =3D + cast(Call->getArgOperand(0)) + ->getZExtValue(); + const uint64_t Offset =3D + cast(Call->getArgOperand(1)) + ->getZExtValue(); + assert(TypeIndex < TcgGlobals.size()); + auto It =3D TcgGlobals[TypeIndex].find(Offset); + assert(It !=3D TcgGlobals[TypeIndex].end()); + const TcgGlobal Global =3D It->second; + TAD.Map[&I] =3D TcgV::makeConstantExpression( + Global.Code.str(), + *ValueSize::fromBitWidth(Global.Size), IrValue); + } break; + default: + continue; + } + } break; + default: + continue; + } + } + } + return Error::success(); +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381146; cv=none; d=zohomail.com; s=zohoarc; b=Ij5m682febPCsmcY4yiQyl3c59TevnkrTww34QndudBPH6WZJkkTSmX/70aJvr9pt4aRtfZwDNkFo+V6nr2ixohwNz0o+sg6qR6RsjI93eOkvP1+853FWsb2CNtVmMMg1f0abRMG/sCyasywIZX5m1vZE5wdCI7JiNDwio7Vn/o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381146; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=fGHTQOYxORVDqGLsM+GXmVZBjMgTh9ykr1xOxA+pths=; b=at7eVfKpBVY0QR6WxZyHuWdjiylJv4n0xCtc0MA/rUk5VX5GM5fviZ52U7WqKkf0pOI1Ni3hEqYVp+D7Ey6dSKtX4XjyTeGB9XypUtisl+lKob8WRIIwxHpRtHED8nTiCMxh/fXh9vMABrJT0uBQoqpMAKaST1dhhP2aJbgmDDo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178538114635362.036488150165496; Wed, 29 Jul 2026 20:12:26 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7f-0005E2-1J; Wed, 29 Jul 2026 23:07:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7B-0004XT-Uy for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:21 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH74-000300-Pf for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:18 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=fGHTQOYxORVDqGLsM+GXmVZBjMgTh9ykr1xOxA+pths=; b=Fgb+JDWpIioEjbV Vf0UqZ1H5q6lVOTl8RJS9amkLYNpJm60eobMYt66mbURN8b+pl3O43FxLU5IXOizPWjbxSF0mkBx6 pwWRMjab8szAdFFZxDtNPyn1WfvOe9bIq9BCUwdfDQDyiJUur9pzgoJYzIjQOGk1DHrh5AL2YPncz V4=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 36/50] helper-to-tcg: TcgGenPass, allocate TCG registers Date: Thu, 30 Jul 2026 05:10:10 +0200 Message-ID: <20260730031025.12926-37-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381148207158500 Content-Type: text/plain; charset="utf-8" Based on the assumption of a cycle free IR, this commit adds a simple register allocator for emitted values in TCG. The goal of this pass is to reduce the number of temporaries required in the output code, which is especially important when dealing with gvec vectors as to not require huge amounts of temporary storage in CPUArchState. For each LLVM value in the IR, that has not already been mapped (arguments, constant expressions), the allocator will assign a `struct TcgV` reprensenting a variable in the output TCG. Signed-off-by: Anton Johansson --- subprojects/helper-to-tcg/meson.build | 1 + .../src/TcgGenPass/MapTemporaries.cpp | 619 ++++++++++++++++++ 2 files changed, 620 insertions(+) create mode 100644 subprojects/helper-to-tcg/src/TcgGenPass/MapTemporaries= .cpp diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 046cdb916b..7ceac955bd 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -53,6 +53,7 @@ sources =3D [ 'src/TcgGenPass/TcgEmit.cpp', 'src/TcgGenPass/MapArguments.cpp', 'src/TcgGenPass/MapConstantExpressions.cpp', + 'src/TcgGenPass/MapTemporaries.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/TcgGenPass/MapTemporaries.cpp b/= subprojects/helper-to-tcg/src/TcgGenPass/MapTemporaries.cpp new file mode 100644 index 0000000000..84f90eba8a --- /dev/null +++ b/subprojects/helper-to-tcg/src/TcgGenPass/MapTemporaries.cpp @@ -0,0 +1,619 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "DebugInfo.hpp" +#include "ValueMapping.hpp" + +#include "CmdLineOptions.hpp" +#include "Error.hpp" +#include "LlvmCompat.hpp" +#include "PseudoInst.hpp" +#include "TcgEmit.hpp" +#include "TcgType.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_TYPE "map-temporaries" + +using namespace llvm; + +// +// TCG Register Allocation Pass +// +// Analysis over the IR that performs basic register allocation to assign +// identifiers representing TCGv's to all non-argument and non-constant va= lues +// in a given function. +// +// Note: Input code is assumed to be loop free, which drastically simplifi= es +// the register allocation. This assumption is reasonable as we expect code +// with loops to be either unrolled or vectorized, and we currently don't = emit +// for loops in C. +// + +// Type to represent a list of free TcgV's that can be reused when +// we need a new temporary. Exists for the duration of a function, +// and is expected to be small <=3D 8 free TcgV's at any time. +// +// This justifies the type being an array, since iteration times to +// find a free element will be small. +using FreeListVector =3D SmallVector; + +// Finds the first `TcgV` in `FreeList` with a matching `TcgBitWidth` and +// `Kind`. +static TcgV findFreeTcgV(FreeListVector &FreeList, TcgSize Size, TcgKind K= ind) { + for (size_t i =3D 0; i < FreeList.size(); ++i) { + if (Kind !=3D FreeList[i].Kind) { + continue; + } + bool Matches =3D false; + switch (Kind) { + case IrPtrToOffset: + Matches =3D Size.Vec.bytes() =3D=3D FreeList[i].Size.Vec.bytes= (); + break; + case IrValue: + case IrImmediate: + Matches =3D Size.Val.TcgBitWidth =3D=3D FreeList[i].Size.Val.T= cgBitWidth; + break; + case IrPtr: + Matches =3D true; + break; + default: + continue; + } + if (Matches) { + TcgV Tcg =3D FreeList[i]; + // Swap-remove + FreeList[i] =3D FreeList.back(); + FreeList.pop_back(); + return Tcg; + } + } + return {}; +} + +static bool valueIsNonImmediateArg(TempAllocationData &TAD, const Value *V= ) { + if (!isa(V)) { + return false; + } + // Assume arguments have already been mapped at this point. + auto It =3D TAD.Map.find(V); + assert(It !=3D TAD.Map.end()); + return It->second.Kind !=3D IrImmediate; +} + +// +// Functions for mapping an LLVM Value to a TcgV +// + +enum MapValueFlags { + ForceNewValue =3D 1, +}; + +// Given an integer LLVM value assign it to a TcgV, either by creating a n= ew +// one or finding a suitable one on the FreeList +static Expected mapInteger(TempAllocationData &TAD, + const AnnotationMapTy &Annotations, + const DebugInfoMapTy &DebugInfo, + FreeListVector &FreeList, const Value *V, + uint32_t flags) { + auto *Ty =3D cast(V->getType()); + auto Size =3D ValueSize::fromLlvmType(Ty); + if (!Size) { + return Size.takeError(); + } + + StringRef Name =3D getDebugVarName(DebugInfo, V); + + if ((flags & ForceNewValue) !=3D 0) { + auto Tcg =3D TcgV::makeTemp(*Size, IrValue); + Tcg.Name =3D Name; + return TAD.map(V, Tcg); + } else { + // Non-constant integer + + // TODO: This is rather hacky and should be widened in an earlier = pass. + if (auto *ICmp =3D dyn_cast(V)) { + // `icmp` return `i1`s and are used as either 32-bit or 64-bit= TCG + // value in QEMU. Assume the size from operands, otherwise all + // returned values are 32 bits in size, causing a mismatch wit= h TCG. + assert(Size->LlvmBitWidth =3D=3D 1); + auto *IntTy0 =3D + dyn_cast(ICmp->getOperand(0)->getType()); + if (!IntTy0) { + return mkError("Icmp on non-integer type"); + } + auto Size0 =3D ValueSize::fromLlvmType(IntTy0); + if (!Size0) { + return Size.takeError(); + } + Size->TcgBitWidth =3D Size0->TcgBitWidth; + } + + TcgV Tcg =3D findFreeTcgV(FreeList, {.Val =3D *Size}, IrValue); + if (Tcg.Kind !=3D IrInvalid) { + // Found a `TcgV` of the corresponding TCG size, update LLVM s= ize. + Tcg.Size.Val.LlvmBitWidth =3D Size->LlvmBitWidth; + return TAD.map(V, Tcg); + } else { + // Otherwise, create a new value + auto Tcg =3D TcgV::makeTemp(*Size, IrValue); + Tcg.Name =3D Name; + return TAD.map(V, Tcg); + } + } +} + +// Given an vector LLVM value assign it to a `TcgV`, either by creating a = new +// one or finding a suitable one on the `FreeList`. Special care is taken= to +// map individual elements of constant vectors. +static Expected mapVector(TempAllocationData &TAD, + const AnnotationMapTy &Annotations, + const DebugInfoMapTy &DebugInfo, + FreeListVector &FreeList, const Value *V, + VectorType *VecTy, uint32_t flags) { + auto Size =3D VectorSize::fromLlvmType(VecTy); + if (!Size) { + return Size.takeError(); + } + + StringRef Name =3D getDebugVarName(DebugInfo, V); + + // TODO: Hacky, avoids comparison results being `` which doesn= 't map + // nicely to TCG, obtain size from argument instead. + if (auto *ICmp =3D dyn_cast(V)) { + auto *VecTy =3D cast(ICmp->getOperand(0)->getType()); + Size =3D VectorSize::fromLlvmType(VecTy); + if (!Size) { + return Size.takeError(); + } + } + + // Create or find a `TcgV` + TcgV Tcg =3D findFreeTcgV(FreeList, {.Vec =3D *Size}, IrPtrToOffset); + if (Tcg.Kind !=3D IrInvalid) { + Tcg.Size.Vec =3D *Size; + } else { + Tcg =3D TcgV::makeVector(*Size); + Tcg.Name =3D Name; + } + + return TAD.map(V, Tcg); +} + +// Given an pointer LLVM value assign it to a TcgV, either by creating a n= ew +// one or finding a suitable one on the FreeList. +static Expected mapPointer(TempAllocationData &TAD, + const AnnotationMapTy &Annotations, + const DebugInfoMapTy &DebugInfo, + FreeListVector &FreeList, const Value *V, + uint32_t flags) { + // If the value has an associated name from the debug information, use= it + StringRef Name{}; + if (auto It =3D DebugInfo.find(V); It !=3D DebugInfo.end()) { + Name =3D It->second.VarName; + } + + if (auto *Alloca =3D dyn_cast(V)) { + // `alloca`s represent stack variables in LLVM IR and return + // pointers, we can simply map them to `IrValue`s + auto *IntTy =3D dyn_cast(Alloca->getAllocatedType()); + if (!IntTy) { + return mkError("alloca with unsupported type: ", V); + } + + auto Size =3D ValueSize::fromLlvmType(IntTy); + if (!Size) { + return Size.takeError(); + } + + // find or create a new `IrValue` + TcgV Tcg =3D findFreeTcgV(FreeList, {.Val =3D *Size}, IrValue); + if (Tcg.Kind !=3D IrInvalid) { + return TAD.map(V, Tcg); + } else { + auto Tcg =3D TcgV::makeTemp(*Size, IrValue); + Tcg.Name =3D Name; + return TAD.map(V, Tcg); + } + } else { + // Otherwise, find or create a new IrPtr of the target pointer size + TcgV Tcg =3D findFreeTcgV(FreeList, {}, IrPtr); + if (Tcg.Kind !=3D IrInvalid) { + return TAD.map(V, Tcg); + } else { + auto Tcg =3D TcgV::makeTemp({}, IrPtr); + Tcg.Name =3D Name; + return TAD.map(V, Tcg); + } + } + + return mkError("Unable to map constant ", V); +} + +// Given a LLVM value, assigns a TcgV by type (integer, pointer, vector). = If +// the given value has already been mapped to a TcgV, return it. +static Expected mapValue(TempAllocationData &TAD, + const AnnotationMapTy &Annotations, + const DebugInfoMapTy &DebugInfo, + FreeListVector &FreeList, const Value *V, + uint32_t flags =3D 0) { + // Return previously mapped value + auto It =3D TAD.Map.find(V); + if (It !=3D TAD.Map.end()) { + return It->second; + } + + if (isa(V)) { + return mkError("Unable to map undefined value: ", V); + } + + Type *Ty =3D V->getType(); + if (isa(Ty)) { + return mapInteger(TAD, Annotations, DebugInfo, FreeList, V, flags); + } else if (isa(Ty)) { + return mapPointer(TAD, Annotations, DebugInfo, FreeList, V, flags); + } else if (isa(Ty)) { + return mapVector(TAD, Annotations, DebugInfo, FreeList, V, + cast(Ty), flags); + } + + return mkError("Unable to map value ", V); +} + +static bool shouldSkipInstruction(const Instruction *const I, + bool SkipReturnMov) { + // Skip returns if we're skipping return mov's + if (isa(I) and SkipReturnMov) { + return true; + } + // Skip assertions + auto Call =3D dyn_cast(I); + if (!Call) { + return false; + } + Function *F =3D Call->getCalledFunction(); + if (!F) { + return false; + } + StringRef Name =3D F->getName(); + return (Name =3D=3D "__assert_fail" or Name =3D=3D "g_assertion_messag= e_expr" or + isa(I) or isa(I) or + isa(I)); +} + +static bool shouldSkipValue(const Value *const V) { + return (isa(V) or isa(V) or isa= (V)); +} + +// A mapping of the return TCG variable to the value `RetV` is valid +// if no use of argument occurs beetween `RetV`s definition and use, this = is to +// avoid clobbers. Iteration may start in the middle of a basic block. +static bool isRetMapValid(TempAllocationData &TAD, + LinearBlocks::const_reverse_iterator BeginBB, + LinearBlocks::const_reverse_iterator EndBB, + BasicBlock::const_reverse_iterator BeginInst, + BasicBlock::const_reverse_iterator EndInst, + const Value *RetV) { + auto ItBB =3D BeginBB; + auto ItInst =3D BeginInst; + + do { + do { + const Instruction &I =3D *ItInst; + // Check if we found definition of `RetV`. + if (cast(&I) =3D=3D RetV) { + return true; + } + // Check for use of non-immediate arguments. + for (auto &V : getOperands(&I)) { + if (valueIsNonImmediateArg(TAD, V)) { + return false; + } + } + } while (++ItInst !=3D EndInst); + + if (++ItBB !=3D EndBB) { + EndInst =3D (*ItBB)->rend(); + ItInst =3D (*ItBB)->rbegin(); + } + } while (ItBB !=3D EndBB); + + return false; +} + +static bool valueIsReference(const Value *V) { + if (auto *Call =3D dyn_cast(V)) { + auto *F =3D Call->getCalledFunction(); + if (AllowDeclCall && F->isDeclaration()) { + return true; + } + } + return false; +} + +static bool instructionClobbersArguments(const Instruction *I) { + if (auto *Call =3D dyn_cast(I)) { + auto *F =3D Call->getCalledFunction(); + if (AllowDeclCall && F->isDeclaration() and + !compat::isFunctionQemuHelper(F->getName())) { + return true; + } else if (F->isIntrinsic() and + F->getIntrinsicID() =3D=3D Intrinsic::usub_sat) { + // TODO: usub_sat maps to tcg_gen_ussub_*() which clobbers + // arguments, if this changes on QEMUs end get rid of this. + return true; + } + } + return false; +} + +static void removeDefinedVariable(TempAllocationData &TAD, + FreeListVector &FreeList, + const Instruction *I) { + auto It =3D TAD.Map.find(cast(I)); + if (!isa(I) and It !=3D TAD.Map.end() and + !cast(I)->getType()->isVoidTy()) { + TcgV &Tcg =3D It->second; + switch (Tcg.Kind) { + case IrValue: + case IrPtr: + case IrPtrToOffset: + FreeList.push_back(Tcg); + break; + case IrImmediate: + break; + default: + abort(); + } + } +} + +Error allocateTemporaries(const Function &F, const LinearBlocks &Blocks, + const AnnotationMapTy &Annotations, + const DebugInfoMapTy &DebugInfo, CEmitter &C, + const TcgGlobalMap &TcgGlobals, + TempAllocationData &TAD) { + FreeListVector FreeList; + + LLVM_DEBUG(dbgs() << "Allocating temporaries for " << F.getName() << "= \n"); + + // The PrepareForOptPass removes all functions with non-int/void return + // types, assert this assumption. + Type *RetTy =3D F.getReturnType(); + assert(isa(RetTy) or RetTy->isVoidTy()); + // Map integer return values + if (auto IntTy =3D dyn_cast(RetTy)) { + auto Size =3D ValueSize::fromLlvmType(IntTy); + if (!Size) { + return Size.takeError(); + } + TAD.flags |=3D ReturnsValue; + TAD.ReturnValue =3D TcgV::makeTemp(*Size, IrValue); + } + + // Skip mov's to return value if possible, results of previous + // instructions might have been assigned the return value. + // + // This is possible if: + // 1. The return value is not an argument. + // 2. The return value is not a constant. + // 3. No use of an argument has occured after the definition of the + // value being returned. + { + auto Begin =3D Blocks.rbegin(); + auto End =3D Blocks.rend(); + const Instruction &I =3D *(*Begin)->rbegin(); + + auto Ret =3D dyn_cast(&I); + if (Ret and Ret->getNumOperands() =3D=3D 1) { + Value *RetV =3D Ret->getReturnValue(); + bool ValidRetV =3D !isa(RetV) and !isa(= RetV); + bool ValidMap =3D isRetMapValid(TAD, Begin, End, (*Begin)->rbe= gin(), + (*Begin)->rend(), RetV); + if (ValidRetV and ValidMap) { + assert(TAD.hasReturnValue()); + TAD.Map.try_emplace(RetV, TAD.ReturnValue); + TAD.flags |=3D SkipReturnMov; + } + } + } + + // Iterate over instructions in reverse and try to allocate TCG + // variables. + // + // The algorithm is very straight forward, we keep a FreeList of TCG + // variables we can reuse. Variables are allocated on first use and + // "freed" on definition. + // + // We allow reuse of the return TCG variable in order to save one + // variable and skip the return mov if possible. Since source and + // return variables can overlap, when take the conservative route and + // only allow reuse of the return variable if no arguments have been + // used. + + bool SeenArgUse =3D false; + + for (auto ItBB =3D Blocks.rbegin(), ItBBEnd =3D Blocks.rend(); ItBB != =3D ItBBEnd; + ++ItBB) { + const BasicBlock *BB =3D *ItBB; + // Loop over instructions in the basic block in reverse + for (auto ItInst =3D BB->rbegin(), ItInstEnd =3D BB->rend(); + ItInst !=3D ItInstEnd; ++ItInst) { + const Instruction &I =3D *ItInst; + if (shouldSkipInstruction(&I, TAD.flags & SkipReturnMov)) { + continue; + } + + { + auto It =3D TAD.Map.find(&I); + if (It !=3D TAD.Map.end() and (It->second.Kind =3D=3D IrIm= mediate or + It->second.ConstantExpression= )) { + continue; + } + } + + LLVM_DEBUG(dbgs() << " For: " << I << "\n"); + + // For calls to the identity mapping pseudo instruction + // we simply want to propagate the type allocated for the resu= lt + // of the call to the operand. + if (isa(&I)) { + auto *Call =3D cast(&I); + PseudoInst Inst =3D getPseudoInstFromCall(Call); + if (Inst =3D=3D IdentityMap) { + Value *Arg =3D Call->getArgOperand(0); + auto It =3D TAD.Map.find(cast(&I)); + assert(It !=3D TAD.Map.end()); + const TcgV Original =3D It->second; + LLVM_DEBUG(dbgs() << " Identity mapping"); + if (TAD.Map.find(Arg) !=3D TAD.Map.end()) { + LLVM_DEBUG(dbgs() << " (forward)\n"); + // Propagate forward + Expected Tcg =3D mapValue(TAD, Annotations, + DebugInfo, FreeList,= Arg); + assert(Tcg); + + TcgV Propagated =3D Tcg.get(); + // If we're identity mapped to an argument we might + // lose vector information if we propagate forward + // blindly, ensure vector type remains, likewise f= or + // scalar we might bit width. + if (Original.Kind =3D=3D IrPtrToOffset) { + Propagated.Kind =3D IrPtrToOffset; + Propagated.Size =3D Original.Size; + } else { + Propagated.Size.Val.LlvmBitWidth =3D + Original.Size.Val.LlvmBitWidth; + } + TAD.Map[cast(&I)] =3D Propagated; + + LLVM_DEBUG({ + dbgs() << "Original:\n"; + Original.dump(dbgs()); + dbgs() << "Arg:\n"; + Tcg->dump(dbgs()); + dbgs() << "Ret:\n"; + Propagated.dump(dbgs()); + }); + } else { + LLVM_DEBUG(dbgs() << " (forward)\n"); + // Propagate back + TcgV Propagated =3D It->second; + // TODO: + if (auto *IntTy =3D + dyn_cast(Arg->getType())) { + auto NewSize =3D ValueSize::fromLlvmType(IntTy= ); + assert(NewSize); + Propagated.Size.Val.LlvmBitWidth =3D + Original.Size.Val.LlvmBitWidth; + } + TAD.Map[Arg] =3D Propagated; + + LLVM_DEBUG({ + dbgs() << "Original:\n"; + Original.dump(dbgs()); + dbgs() << "Ret:\n"; + Propagated.dump(dbgs()); + }); + } + + continue; + } + } + + // Check if we've encountered any non-immediate argument yet + for (const Use &U : getOperands(&I)) { + if (valueIsNonImmediateArg(TAD, U)) { + SeenArgUse =3D true; + } + } + + // Free up variables as they are defined, iteration is in post + // order meaning uses of vars always occur before definitions. + bool AllowDestReuse =3D !instructionClobbersArguments(&I); + if (AllowDestReuse) { + removeDefinedVariable(TAD, FreeList, &I); + } + + // Loop over operands and assign TcgV's. On first encounter of= a + // given operand we assign a new TcgV from the FreeList. + for (const Use &V : getOperands(&I)) { + auto It =3D TAD.Map.find(V); + if (It !=3D TAD.Map.end() or shouldSkipValue(V)) { + continue; + } + + uint32_t Flags =3D 0; + if (valueIsReference(V)) { + Flags |=3D ForceNewValue; + } + + Expected Tcg =3D + mapValue(TAD, Annotations, DebugInfo, FreeList, V, Fla= gs); + if (!Tcg) { + return Tcg.takeError(); + } + + LLVM_DEBUG({ + dbgs() << " Arg: " << *V << "\n"; + Tcg->dump(dbgs()); + }); + + // If our value V got mapped to the return value, + // make sure the mapping is valid + // + // A mapping to the return value is valid as long as + // an argument has not been used. This is to prevent + // clobbering in the case that arguments and the return + // value overlap. + if (TAD.hasReturnValue() and *Tcg =3D=3D TAD.ReturnValue) { + bool Valid =3D + isRetMapValid(TAD, ItBB, ItBBEnd, ItInst, ItInstEn= d, V); + if (!SeenArgUse and Valid) { + continue; + } + + // The mapping was not valid, erase it and assign a new + // one, this takes the return `TcgV` of out the `freel= ist` + // pool. + TAD.Map.erase(V); + Expected Tcg =3D mapValue(TAD, Annotations, Debu= gInfo, + FreeList, V, Flags); + if (!Tcg) { + return Tcg.takeError(); + } + } + } + + // Free up variables as they are defined, iteration is in post + // order meaning uses of vars always occur before definitions. + if (!AllowDestReuse) { + removeDefinedVariable(TAD, FreeList, &I); + } + } + } + + return Error::success(); +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381036; cv=none; d=zohomail.com; s=zohoarc; b=URuLZcirw+IU+hHRUuGMyUxEe2ajufkQBYpppeB92Lzxo2+bSgCJ2PCqzyWktKKfUK25Zg4qmdNV7PcfoD2aMnGABf3Mz7KuLC2dTO04Ks8cyKIinYfkb8JPAv/+OQCMUlR1BeKmaDruQWkINUjC4NgZqpSW5KEDxfHXHOFut9A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381036; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=nLIbjVVzkkUkumGSG8gBepSWDpXnJeP5cw13McXLPI8=; b=mBPleS3GkXfOn0Z4mXtBjW8bMQEe//jEzzBaujN/Zn9aUqn9TQcvaXqEqZsNrPdOGXXkDrKwvq4nKIb0yoB36uOBAX/TD9CwK6BA/Lh+vA1GNqTkxQtiThYfD6GHoSnw9B7GetSNWJbiXUwm20uUc8FVAI1k7FZLPMxumsMvDvM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381036805682.8898166023654; Wed, 29 Jul 2026 20:10:36 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7b-00057o-G0; Wed, 29 Jul 2026 23:07:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7H-0004gz-QD for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:29 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7C-00030D-4k for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=nLIbjVVzkkUkumGSG8gBepSWDpXnJeP5cw13McXLPI8=; b=iEak9WVNSlpvXn6 ZqIOftX76YGVPQhsIiFtqj7Luk9nR97iULp8oTyZPfVKQdRHfK3iTEykmPifprNFZZN2a07GKiz6C s/KwjgvMkzoZKY/SOHvzebkCSu0esKfsk4x8G+xQX509uTWBp5IRq4AlC3HNjFprXDFP7o5+n0TeX /4=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 37/50] helper-to-tcg: TcgGenPass, emit TCG strings Date: Thu, 30 Jul 2026 05:10:11 +0200 Message-ID: <20260730031025.12926-38-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381037786158500 Content-Type: text/plain; charset="utf-8" Forward pass over the IR which uses previosly mapped LLVM values to emit the corresponding operations in TCG. Signed-off-by: Anton Johansson --- subprojects/helper-to-tcg/meson.build | 1 + .../src/TcgGenPass/MapTcgOperations.cpp | 988 ++++++++++++++++++ 2 files changed, 989 insertions(+) create mode 100644 subprojects/helper-to-tcg/src/TcgGenPass/MapTcgOperatio= ns.cpp diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 7ceac955bd..413d7ad8fa 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -54,6 +54,7 @@ sources =3D [ 'src/TcgGenPass/MapArguments.cpp', 'src/TcgGenPass/MapConstantExpressions.cpp', 'src/TcgGenPass/MapTemporaries.cpp', + 'src/TcgGenPass/MapTcgOperations.cpp', ] =20 clang =3D bindir / 'clang' diff --git a/subprojects/helper-to-tcg/src/TcgGenPass/MapTcgOperations.cpp = b/subprojects/helper-to-tcg/src/TcgGenPass/MapTcgOperations.cpp new file mode 100644 index 0000000000..57cdad2624 --- /dev/null +++ b/subprojects/helper-to-tcg/src/TcgGenPass/MapTcgOperations.cpp @@ -0,0 +1,988 @@ +// +// Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, see . +// + +#include "ValueMapping.hpp" + +#include "CmdLineOptions.hpp" +#include "Error.hpp" +#include "FunctionAnnotation.hpp" +#include "LlvmCompat.hpp" +#include "PseudoInst.hpp" +#include "TcgEmit.hpp" +#include "TcgType.hpp" +#include "ValueMapping.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_TYPE "map-tcg-ops" + +// +// Map TCG Operations +// +// Forward pass over the IR, emitting expressions to TCG using the provided +// `TempAllocationData` value mapping. +// + +using namespace llvm; + +// Wrapper class around a TcgV to cast it to/from 32-/64-bit +class TcgSizeAdapter { + TcgEmitter &TE; + const TcgV Orig; + TcgV Adapted; + + public: + TcgSizeAdapter(TcgEmitter &TE, const TcgV Orig) : TE(TE), Orig(Orig) {} + + const TcgV get(ValueSize Size) { + const ValueSize OrigSize =3D Orig.intSize(); + if (Orig.Kind =3D=3D IrImmediate or + (OrigSize.TcgBitWidth =3D=3D Size.TcgBitWidth)) { + return Orig; + } else if (Adapted.Kind =3D=3D IrInvalid) { + initAdapted(Size.TcgBitWidth); + } + return Adapted; + } + + private: + void initAdapted(AllowedTcgSize Size) { + assert(Adapted.Kind =3D=3D IrInvalid); + const ValueSize OrigSize =3D Orig.intSize(); + assert(OrigSize.TcgBitWidth !=3D Size); + Adapted =3D TcgV::makeTemp({Size, OrigSize.LlvmBitWidth}, Orig.Kin= d); + TE.defineNewTemp(Adapted); + if (Size =3D=3D 32) { + TE.genExtrlI64I32(Adapted, Orig); + } else { + TE.genExtuI32I64(Adapted, Orig); + } + } +}; + +enum class LabelKind : uint8_t { + Tcg, + If, + Else, + Merge, +}; + +struct LabelInfo { + LabelKind Kind; + TcgV Label; +}; + +class Mapper { + TcgEmitter &TE; + const TempAllocationData &TAD; + + llvm::DenseMap Labels; + // Keep track of whether a TcgV has been defined already, or not + SmallBitVector HasBeenDefined; + + public: + Mapper(TcgEmitter &TE, const TempAllocationData &TAD) : TE(TE), TAD(TA= D) { + // Default to size of previously mapped TcgVs + HasBeenDefined.resize(TAD.Map.size()); + } + + bool hasBeenDefined(const TcgV &V) { return HasBeenDefined[V.Id]; } + + void define(const TcgV &V) { HasBeenDefined.set(V.Id); } + + LabelInfo mapBbAndEmit(BasicBlock *BB, LabelKind Kind =3D LabelKind::T= cg) { + auto It =3D Labels.find(BB); + if (It =3D=3D Labels.end()) { + TcgV Label =3D TcgV::makeLabel(); + if (Kind =3D=3D LabelKind::Tcg) { + TE.defineNewTemp(Label); + } + return Labels.try_emplace(BB, LabelInfo{Kind, Label}).first->s= econd; + } + return It->second; + } + + TcgV mapTcgLabel(BasicBlock *BB) { + const LabelInfo LI =3D mapBbAndEmit(BB); + assert(LI.Kind =3D=3D LabelKind::Tcg); + return LI.Label; + } + + const TcgV defineValue(const Value *V, bool ForceNondef =3D false) { + // `Value` should have already been mapped by previous passes. + auto It =3D TAD.Map.find(V); + assert(It !=3D TAD.Map.end()); + const TcgV Tcg =3D It->second; + + // Using that `TcgV` ids are sequential for a function and start + // from 0. + // TODO: Might be nice to just track a maximum from previous passe= s. + if (Tcg.Id >=3D HasBeenDefined.size()) { + HasBeenDefined.resize(Tcg.Id + 1); + } + if (!HasBeenDefined[Tcg.Id]) { + if (!isa(V) and + (!TAD.hasReturnValue() or Tcg !=3D TAD.ReturnValue) and + !Tcg.ConstantExpression and Tcg.Kind !=3D IrImmediate) { + if (!ForceNondef) { + HasBeenDefined.set(Tcg.Id); + TE.defineNewTemp(Tcg); + } + } + } + + return Tcg; + } +}; + +static void ensureSignBitIsSet(TcgEmitter &TE, const TcgV &Tcg) { + const ValueSize Size =3D Tcg.intSize(); + if (Tcg.llvmBitWidth() =3D=3D Tcg.tcgBitWidth() or Tcg.Kind !=3D IrVal= ue) { + return; + } + TE.genExtract( + true, Tcg, Tcg, TcgV::makeImmediate("0", Size), + TcgV::makeImmediate(Twine((int)Size.LlvmBitWidth).str(), Size)); +} + +static const TcgV mapCallReturnValue(Mapper &Mapper, CallInst *Call, + bool CallToDecl =3D false) { + // Only map return value if it has > 0 uses. Destination values of ca= ll + // instructions are the only ones which LLVM will not remove if unused. + if (Call->getType()->isVoidTy() or Call->getNumUses() =3D=3D 0) { + return {}; + } + return Mapper.defineValue(Call, CallToDecl); +} + +static Instruction::BinaryOps mapPseudoInstToOpcode(PseudoInst Inst) { + switch (Inst) { + case VecAddScalar: + case VecAddStore: + case VecAddScalarStore: + return Instruction::Add; + case VecSubScalar: + case VecSubStore: + case VecSubScalarStore: + return Instruction::Sub; + case VecMulScalar: + case VecMulStore: + case VecMulScalarStore: + return Instruction::Mul; + case VecXorScalar: + case VecXorStore: + case VecXorScalarStore: + return Instruction::Xor; + case VecOrScalar: + case VecOrStore: + case VecOrScalarStore: + return Instruction::Or; + case VecAndScalar: + case VecAndStore: + case VecAndScalarStore: + return Instruction::And; + case VecShlScalar: + case VecShlStore: + case VecShlScalarStore: + return Instruction::Shl; + case VecLShrScalar: + case VecLShrStore: + case VecLShrScalarStore: + return Instruction::LShr; + case VecAShrScalar: + case VecAShrStore: + case VecAShrScalarStore: + return Instruction::AShr; + default: + abort(); + } +} + +static bool translatePseudoInstCall(CEmitter &CE, TcgEmitter &TE, + CallInst *Call, PseudoInst PInst, + Mapper &Mapper, + const TcgGlobalMap &TcgGlobals, + const TcgV &Ret, + ArrayRef Args) { + switch (PInst) { + case IdentityMap: { + // Nothing to do + } break; + case GetPC: { + TE.genCallHelper("helper_getpc", {Ret}); + } break; + case PtrAdd: { + assert(Args[0].Kind =3D=3D IrPtr or Args[0].Kind =3D=3D IrPtrToOff= set); + if (Args[0].Kind =3D=3D IrPtr) { + TE.genAddPtr(Ret, Args[0], Args[1]); + } else { + assert(Args[1].Kind =3D=3D IrValue); + TE.genValueToPtr(Ret, Args[1]); + TE.genAddPtr(Ret, Ret, Args[0]); + TE.genAddPtr(Ret, Ret, TE.getGlobalEnv()); + } + } break; + case Brcond: { + bool Fallthrough =3D + cast(Call->getOperand(0))->getZExtValue(); + auto LlvmPred =3D static_cast( + cast(Call->getOperand(1))->getZExtValue()); + TE.genBrcond(LlvmPred, Args[2], Args[3], Args[4]); + if (!Fallthrough) { + TE.genBr(Args[5]); + } + } break; + case Movcond: { + auto LlvmPred =3D static_cast( + cast(Call->getOperand(0))->getZExtValue()); + if (CmpInst::isSigned(LlvmPred)) { + // Since comprasions are made on TCG registers which contains + // smaller logical LLVM values, make sure to correctly sign ex= tend + // smaller values for comparisons. + ensureSignBitIsSet(TE, Args[1]); + ensureSignBitIsSet(TE, Args[2]); + } + TE.genMovcond(LlvmPred, Ret, Args[1], Args[2], Args[3], Args[4]); + } break; + case VecSplat: { + TE.genVecSplat(Ret, Args[0]); + } break; + case VecConstant: { + TE.genVecArrSplat(Ret, Args[0]); + } break; + case VecNot: { + TE.genVecNot(Ret, Args[0]); + } break; + case VecNotStore: { + TE.genVecNot(Args[0], Args[1]); + } break; + case VecAddScalar: + case VecSubScalar: + case VecMulScalar: + case VecXorScalar: + case VecOrScalar: + case VecAndScalar: + case VecShlScalar: + case VecLShrScalar: + case VecAShrScalar: { + auto Opcode =3D mapPseudoInstToOpcode(PInst); + TE.genVecBinOp(Opcode, Ret, Args[0], Args[1]); + } break; + case VecAddStore: + case VecSubStore: + case VecMulStore: + case VecXorStore: + case VecOrStore: + case VecAndStore: + case VecShlStore: + case VecLShrStore: + case VecAShrStore: + case VecAddScalarStore: + case VecSubScalarStore: + case VecMulScalarStore: + case VecXorScalarStore: + case VecOrScalarStore: + case VecAndScalarStore: + case VecShlScalarStore: + case VecLShrScalarStore: + case VecAShrScalarStore: { + auto Opcode =3D mapPseudoInstToOpcode(PInst); + TE.genVecBinOp(Opcode, Args[0], Args[1], Args[2]); + } break; + case VecSignedSatAddStore: { + TE.genVecSignedSatAdd(Args[0], Args[1], Args[2]); + } break; + case VecSignedSatSubStore: { + TE.genVecSignedSatSub(Args[0], Args[1], Args[2]); + } break; + case VecSelectStore: { + TE.genVecBitsel(Args[0], Args[1], Args[2], Args[3]); + } break; + case VecAbsStore: { + TE.genAbs(Args[0], Args[1]); + } break; + case VecSignedMaxStore: { + TE.genVecSignedMax(Args[0], Args[1], Args[2]); + } break; + case VecUnsignedMaxStore: { + TE.genVecUnsignedMax(Args[0], Args[1], Args[2]); + } break; + case VecSignedMinStore: { + TE.genVecSignedMin(Args[0], Args[1], Args[2]); + } break; + case VecUnsignedMinStore: { + TE.genVecUnsignedMin(Args[0], Args[1], Args[2]); + } break; + case VecTruncStore: { + uint8_t DstElementBits =3D + cast(Call->getOperand(0))->getZExtValue(); + TE.genVecTrunc(DstElementBits, Args[1], Args[2]); + } break; + case VecCompare: { + auto LlvmPred =3D static_cast( + cast(Call->getOperand(0))->getZExtValue()); + TE.genVecCmp(Ret, LlvmPred, Args[1], Args[2]); + } break; + case VecWideCondBitsel: { + TE.genVecBitsel(Ret, Args[0], Args[1], Args[2]); + break; + } break; + case VecWideCondBitselStore: { + TE.genVecBitsel(Args[0], Args[1], Args[2], Args[3]); + break; + } break; + case GuestLoad: { + uint8_t Sign =3D cast(Call->getOperand(1))->getZExtVa= lue(); + uint8_t Size =3D cast(Call->getOperand(2))->getZExtVa= lue(); + uint8_t Endianness =3D + cast(Call->getOperand(3))->getZExtValue(); + TE.genGuestLoad(Ret, TE.materialize(Args[0]), + TE.getMemOp(Size, Endianness, Sign)); + } break; + case GuestStore: { + uint8_t Size =3D cast(Call->getOperand(2))->getZExtVa= lue(); + uint8_t Endianness =3D + cast(Call->getOperand(3))->getZExtValue(); + TE.genGuestStore(Args[0], Args[1], TE.getMemOp(Size, Endianness, 0= )); + } break; + case Exception: { + // Map and adapt arguments to the call + SmallVector IArgs; + for (auto Arg : Args) { + IArgs.push_back(TE.materialize(Arg)); + } + TE.genCallHelper("helper_raise_exception", IArgs.begin(), IArgs.en= d()); + } break; + default: + // unmapped pseudo inst + return false; + } + return true; +} + +static bool translateIntrinsicCall(TcgEmitter &TE, CallInst *Call, Functio= n *F, + const TcgV &Ret, ArrayRef Args, + Mapper &Mapper) { + switch (F->getIntrinsicID()) { + case Intrinsic::abs: { + TE.genAbs(Ret, Args[0]); + } break; + case Intrinsic::smax: { + TE.genVecSignedMax(Ret, Args[0], Args[1]); + } break; + case Intrinsic::smin: { + TE.genVecSignedMin(Ret, Args[0], Args[1]); + } break; + case Intrinsic::umax: { + TE.genVecUnsignedMax(Ret, Args[0], Args[1]); + } break; + case Intrinsic::umin: { + TE.genVecUnsignedMin(Ret, Args[0], Args[1]); + } break; + case Intrinsic::sadd_sat: { + TE.genVecSignedSatAdd(Ret, Args[0], Args[1]); + } break; + case Intrinsic::ssub_sat: { + TE.genVecSignedSatSub(Ret, Args[0], Args[1]); + } break; + case Intrinsic::usub_sat: { + if (Args[0].Kind =3D=3D IrPtrToOffset) { + TE.genVecUnsignedSatSub(Ret, Args[0], Args[1]); + } else { + TE.genUnsignedSatSub(Ret, Args[0], Args[1]); + } + } break; + case Intrinsic::ctlz: { + if (Args[0].Kind =3D=3D IrPtrToOffset) { + // no gvec equivalent to clzi + return false; + } + TE.genCountLeadingZeros(Ret, Args[0]); + } break; + case Intrinsic::cttz: { + if (Args[0].Kind =3D=3D IrPtrToOffset) { + // no gvec equivalent to ctti + return false; + } + TE.genCountTrailingZeros(Ret, Args[0]); + } break; + case Intrinsic::ctpop: { + if (Args[0].Kind =3D=3D IrPtrToOffset) { + // no gvec equivalent to ctpop + return false; + } + TE.genCountOnes(Ret, Args[0]); + } break; + case Intrinsic::bswap: { + TE.genByteswap(Ret, Args[0]); + } break; + case Intrinsic::fshl: { + TE.genFunnelShl(Ret, Args[0], Args[1], Args[2]); + } break; + case Intrinsic::bitreverse: { + TE.genBitreverse(Ret, Args[0]); + } break; + case Intrinsic::memcpy: { + TE.genVecMemcpy(Args[0], Args[1], Args[2]); + } break; + case Intrinsic::memset: { + TE.genVecMemset(Args[0], Args[1], Args[2]); + } break; + default: + // Unhandled LLVM intrinsic + return false; + } + return true; +} + +static Error +translateCall(const TcgGlobalMap &TcgGlobals, + const AnnotationMapTy &AnnotationMap, + const SmallPtrSet &HasTranslatedFunction, + TcgEmitter &TE, CEmitter &CE, Mapper &Mapper, CallInst *Call= ) { + Function *F =3D Call->getCalledFunction(); + if (!F) { + return mkError("Indirect function calls not handled: ", Call); + } + + assert(F->hasName()); + StringRef Name{F->getName()}; + + // Filter out calls we don't care about. Note we don't have to manuall= y deal + // with debug instructions after LLVM 18. + if (Name =3D=3D "__assert_fail" or Name =3D=3D "g_assertion_message_ex= pr" or + Call->isDebugOrPseudoInst() or + (F->isIntrinsic() and + (F->getIntrinsicID() =3D=3D Intrinsic::lifetime_start or + F->getIntrinsicID() =3D=3D Intrinsic::lifetime_end))) { + return Error::success(); + } + + const TcgV Ret =3D mapCallReturnValue(Mapper, Call); + SmallVector Args; + for (unsigned i =3D 0; i < Call->arg_size(); ++i) { + if (auto BB =3D dyn_cast(Call->getArgOperand(i))) { + Args.push_back(Mapper.mapTcgLabel(BB)); + } else { + Args.push_back(Mapper.defineValue(Call->getArgOperand(i))); + } + } + + // Function names sometimes contain embedded type information to + // handle polymorphic arguments, for instance + // + // llvm.memcpy.p0i8.p0i8.i64 + // + // specifying the source and desination pointer types as i8* and + // the size argument as an i64. + // + // Find the index for the first '.' before the types are + // specified + // + // llvm.memcpy.p0i8.p0i8.i64 + // ^- index of this '.' + size_t IndexBeforeTypes =3D StringRef::npos; + for (size_t i =3D Name.size() - 1; i > 0; --i) { + const char c =3D Name[i]; + bool ValidType =3D (c >=3D '0' and c <=3D '9') or c =3D=3D 'i' or = c =3D=3D 'p' or + c =3D=3D 'a' or c =3D=3D 'v' or c =3D=3D 'x'; + if (c =3D=3D '.') { + IndexBeforeTypes =3D i; + } else if (!ValidType) { + break; + } + } + const StringRef StrippedName =3D Name.substr(0, IndexBeforeTypes); + + // TODO: + // + // Calls to [s]extract*() need some cleanup, it's not super obious what + // happens, but if the length and offset arguments are immediates we c= an + // instead map the call directly to a TCG equivalent, otherwise we con= tinue + // down the chain of `if`s until we end up calling emitted code. + // + + if (F->isIntrinsic()) { + if (!translateIntrinsicCall(TE, Call, F, Ret, Args, Mapper)) { + return mkError("Unable to map intrinsic: ", Call); + } + } else if (PseudoInst PInst =3D getPseudoInstFromCall(Call); + PInst !=3D InvalidPseudoInst) { + if (!translatePseudoInstCall(CE, TE, Call, PInst, Mapper, TcgGloba= ls, + Ret, Args)) { + return mkError("Unable to map pseudo inst: ", Call); + } + } else if (StrippedName =3D=3D "extract32" and Args[1].Kind =3D=3D IrI= mmediate and + Args[2].Kind =3D=3D IrImmediate) { + TE.genExtract(false, Ret, Args[0], Args[1], Args[2]); + } else if (StrippedName =3D=3D "extract64" and Args[1].Kind =3D=3D IrI= mmediate and + Args[2].Kind =3D=3D IrImmediate) { + TE.genExtract(false, Ret, Args[0], Args[1], Args[2]); + } else if (StrippedName =3D=3D "sextract32" and Args[1].Kind =3D=3D Ir= Immediate and + Args[2].Kind =3D=3D IrImmediate) { + TE.genExtract(true, Ret, Args[0], Args[1], Args[2]); + } else if (StrippedName =3D=3D "sextract64" and Args[1].Kind =3D=3D Ir= Immediate) { + TE.genExtract(true, Ret, Args[0], + TcgV::makeImmediate("0", Ret.intSize()), Args[1]); + } else if (StrippedName =3D=3D "deposit32" and Args[2].Kind =3D=3D IrI= mmediate and + Args[3].Kind =3D=3D IrImmediate) { + TE.genDeposit(Ret, Args[0], Args[1], Args[2], Args[3]); + } else if (StrippedName =3D=3D "deposit64" and Args[2].Kind =3D=3D IrI= mmediate and + Args[3].Kind =3D=3D IrImmediate) { + TE.genDeposit(Ret, Args[0], Args[1], Args[2], Args[3]); + } else if (compat::isFunctionQemuHelper(Name)) { + // Map and adapt arguments to the call + SmallVector IArgs; + for (auto Arg : Args) { + IArgs.push_back(TE.materialize(Arg)); + } + TE.genCallHelper(Name, IArgs.begin(), IArgs.end()); + } else { + + if (!AllowDeclCall and F->isDeclaration()) { + return mkError("call to declaration: ", Call); + } + + if (!F->isDeclaration() and + HasTranslatedFunction.find(F) =3D=3D HasTranslatedFunction.end= ()) { + return mkError("call to function which failed to translate: ", + Call); + } + + StringRef Name =3D F->getName(); + Name.consume_front("helper_"); + + Annotations Ann{}; + if (auto It =3D AnnotationMap.find(F); It !=3D AnnotationMap.end()= ) { + // TODO: This is an unnecessary copy, we currently + // use that a default constructed `Annotations` will + // return 0 for all argument flags without + // allocating any extra space. + Ann =3D It->second; + } + + SmallVector TcgArgs; + if (ForwardContext) { + TcgArgs.push_back(TE.getDisasContext()); + } + if (!F->isDeclaration() and Ret.Kind !=3D IrInvalid) { + TcgArgs.push_back(Ret); + } + for (size_t I =3D 0; I < Args.size(); ++I) { + if (Ann.isSet(I, ArgumentAnnotation::Immediate)) { + TcgArgs.push_back(Args[I]); + } else { + TcgArgs.push_back(TE.materialize(Args[I])); + } + } + + if (!F->isDeclaration()) { + StackTwine<64> Str =3D Twine("emit_") + Name; + TE.genCallCFunc(Str, {}, TcgArgs.begin(), TcgArgs.end()); + } else { + TE.genCallCFunc(Name, Ret, TcgArgs.begin(), TcgArgs.end()); + } + } + + return Error::success(); +} + +Error mapTcgOperations(const LinearBlocks &Blocks, + const TcgGlobalMap &TcgGlobals, + const AnnotationMapTy &AnnotationMap, + const SmallPtrSet &HasTranslatedFun= ction, + const TempAllocationData &TAD, TcgEmitter &TE, + CEmitter &CE) { + Mapper Mapper(TE, TAD); + for (BasicBlock *BB : Blocks) { + // Set label if not first basic block + if (BB !=3D Blocks[0]) { + const TcgV Label =3D Mapper.mapTcgLabel(BB); + TE.genSetLabel(Label); + } + + // Emit TCG generators for the current BB + for (Instruction &I : *BB) { + if (TAD.Map.lookup(&I).Kind =3D=3D IrImmediate or + TAD.Map.lookup(&I).ConstantExpression) { + continue; + } + + switch (I.getOpcode()) { + case Instruction::Alloca: { + auto Alloca =3D cast(&I); + Mapper.defineValue(Alloca); + } break; + case Instruction::Br: { + auto Branch =3D cast(&I); + if (Branch->isConditional()) { + assert(Branch->getNumSuccessors() =3D=3D 2); + const TcgV Condition =3D + Mapper.defineValue(Branch->getCondition()); + const TcgV CCondition =3D TE.materialize(Condition); + const TcgV True =3D + Mapper.mapTcgLabel(Branch->getSuccessor(0)); + const TcgV False =3D + Mapper.mapTcgLabel(Branch->getSuccessor(1)); + + // Jump if condition is !=3D 0 + auto Zero =3D TcgV::makeImmediate("0", CCondition.intS= ize()); + TE.genBrcond(CmpInst::Predicate::ICMP_NE, CCondition, = Zero, + True); + TE.genBr(False); + } else { + const TcgV Label =3D + Mapper.mapTcgLabel(Branch->getSuccessor(0)); + TE.genBr(Label); + } + } break; + case Instruction::SExt: { + auto SExt =3D cast(&I); + + const TcgV Src =3D Mapper.defineValue(SExt->getOperand(0)); + const TcgV Dst =3D Mapper.defineValue(&I); + if (Src.Kind =3D=3D IrPtrToOffset) { + TE.genVecSext(Dst.vecSize().ElementBitWidth, Dst, Src); + } else { + const ValueSize SrcSize =3D Src.intSize(); + const ValueSize DstSize =3D Dst.intSize(); + if (DstSize.LlvmBitWidth < 32) { + return mkError("sext to unsupported size: ", &I); + } + if (SrcSize.LlvmBitWidth > 1 and + SrcSize.LlvmBitWidth < 32) { + auto ASrc =3D TcgSizeAdapter(TE, Src); + TE.genExts(Dst, ASrc.get(DstSize)); + } else if (SrcSize.LlvmBitWidth =3D=3D 1 and + DstSize.TcgBitWidth =3D=3D 32) { + TE.genMov(Dst, Src); + } else { + TE.genExtI32I64(Dst, Src); + } + } + } break; + case Instruction::ZExt: { + auto ZExt =3D cast(&I); + + const TcgV Src =3D Mapper.defineValue(ZExt->getOperand(0)); + const TcgV Dst =3D Mapper.defineValue(&I); + if (Dst.Kind =3D=3D IrValue) { + const ValueSize SrcSize =3D Src.intSize(); + const ValueSize DstSize =3D Dst.intSize(); + if (SrcSize.TcgBitWidth =3D=3D DstSize.TcgBitWidth) { + TE.genMov(Dst, Src); + } else if (SrcSize.TcgBitWidth > DstSize.TcgBitWidth a= nd + SrcSize.LlvmBitWidth =3D=3D 1) { + // Paradoxically we may need to emit an extract + // instruction for when a zero extension is reques= ted. + // This is to account for the fact that "booleans"= in + // tcg can be both 64- and 32-bit. So for instance= zext + // i1 -> i32, here i1 may actually be 64-bit. + TE.genExtrlI64I32(Dst, Src); + } else { + TE.genExtuI32I64(Dst, Src); + } + } else if (Dst.Kind =3D=3D IrPtrToOffset) { + TE.genVecZext(Dst.vecSize().ElementBitWidth, Dst, Src); + } else { + return mkError("Invalid TcgSize!"); + } + } break; + case Instruction::Trunc: { + auto Trunc =3D cast(&I); + + const TcgV Src =3D Mapper.defineValue(Trunc->getOperand(0)= ); + const TcgV Dst =3D Mapper.defineValue(&I); + if (Dst.Kind =3D=3D IrValue) { + const ValueSize SrcSize =3D Src.intSize(); + const ValueSize DstSize =3D Dst.intSize(); + if (SrcSize.TcgBitWidth =3D=3D 64) { + if (DstSize.LlvmBitWidth =3D=3D 32) { + // 64 -> 32 + TE.genExtrlI64I32(Dst, Src); + } else { + // 64 -> 16,8,1 + // TODO:Simplify + auto Offset =3D TcgV::makeImmediate("0", DstSi= ze); + auto Size =3D TcgV::makeImmediate( + Twine((int)Dst.llvmBitWidth()).str(), DstS= ize); + auto Temp =3D TcgV::makeTemp({T64, I64}, IrVal= ue); + TE.defineNewTemp(Temp); + TE.genExtract(false, Temp, Src, Offset, Size); + TE.genExtrlI64I32(Dst, Temp); + } + } else { + // 32 -> 16,8,1 + // 16 -> 8,1 + // 8 -> 1 + auto Offset =3D TcgV::makeImmediate("0", DstSize); + auto Size =3D TcgV::makeImmediate( + Twine((int)Dst.llvmBitWidth()).str(), DstSize); + TE.genExtract(false, Dst, Src, Offset, Size); + } + } else if (Dst.Kind =3D=3D IrPtrToOffset) { + TE.genVecTrunc(Dst.vecSize().ElementBitWidth, Dst, Src= ); + } else { + abort(); + } + } break; + case Instruction::Add: + case Instruction::And: + case Instruction::AShr: + case Instruction::LShr: + case Instruction::Mul: + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::Or: + case Instruction::Shl: + case Instruction::Sub: + case Instruction::Xor: { + auto Bin =3D cast(&I); + // Check we are working on integers + TcgV Op1 =3D Mapper.defineValue(Bin->getOperand(0)); + TcgV Op2 =3D Mapper.defineValue(Bin->getOperand(1)); + const TcgV Res =3D Mapper.defineValue(Bin); + + // Swap operands if the first op. is an immediate + // and the operator is commutative + if (Op1.Kind =3D=3D IrImmediate and Op2.Kind !=3D IrImmedi= ate and + Bin->isCommutative()) { + std::swap(Op1, Op2); + } + + if (Res.Kind =3D=3D IrValue) { + // Adapt sizes to account for boolean values where + // `LlvmSize` is 1, and `TcgSize` is either 32 or 64. + // + // Also materialize both arguments to skip trivial + // sanity checks found in `tcg_gen_[op]i*()` since e.g. + // LLVM wouldn't leave an add instruction with a 0 + // operand. This is also important to handle situatio= ns + // such as + // + // TCGv_i32 tmp =3D tcg_temp_new_i32(); + // tcg_gen_shli_i32(tmp, src, arg); + // tcg_gen_movcond_i32(TCG_COND_GTU, res + // tcg_constant_i32(arg), + // tcg_constant_i32(31), + // tcg_constant_i32(0), + // tmp); + // + // where LLVM might produce an "unsafe" operation and + // only guard it afterwards with a conditional move. + // + // TODO: Emitting + // + // if (arg > 31) { + // tcg_gen_movi(res, 0); + // } else { + // tcg_gen_[op]i*(res, src, arg); + // } + // + // is feasible with some help from `canoncializeIR()`. + TcgSizeAdapter AOp1(TE, TE.materialize(Op1)); + TcgSizeAdapter AOp2(TE, TE.materialize(Op2)); + + TE.genBinOp(Res, Bin->getOpcode(), AOp1.get(Res.intSiz= e()), + AOp2.get(Res.intSize())); + } else if (Res.Kind =3D=3D IrPtrToOffset) { + TE.genVecBinOp(Bin->getOpcode(), Res, Op1, Op2); + } + } break; + case Instruction::Call: { + auto Call =3D cast(&I); + auto Err =3D + translateCall(TcgGlobals, AnnotationMap, + HasTranslatedFunction, TE, CE, Mapper, C= all); + if (Err) { + return Err; + } + } break; + case Instruction::ICmp: { + auto *ICmp =3D cast(&I); + const TcgV Op1 =3D Mapper.defineValue(I.getOperand(0)); + const TcgV Op2 =3D Mapper.defineValue(I.getOperand(1)); + const TcgV Res =3D Mapper.defineValue(ICmp); + + ICmpInst::Predicate LlvmPred =3D ICmp->getPredicate(); + + if (Op1.Kind =3D=3D IrPtrToOffset) { + TE.genVecCmp(Res, LlvmPred, Op1, Op2); + } else { + auto IOp1 =3D TE.materialize(Op1); + if (ICmp->isSigned()) { + ensureSignBitIsSet(TE, IOp1); + ensureSignBitIsSet(TE, Op2); + } + TE.genSetcond(LlvmPred, Res, IOp1, Op2); + } + } break; + case Instruction::Select: { + auto Select =3D cast(&I); + const TcgV Res =3D Mapper.defineValue(Select); + + if (Res.Kind =3D=3D IrPtr) { + return mkError( + "Select statements for pointer types not supported= : ", + Select); + } + const TcgV Cond =3D Mapper.defineValue(Select->getConditio= n()); + const TcgV True =3D Mapper.defineValue(Select->getTrueValu= e()); + const TcgV False =3D Mapper.defineValue(Select->getFalseVa= lue()); + + if (Res.Kind =3D=3D IrPtrToOffset) { + TE.genVecBitsel(Res, Cond, True, False); + } else if (Cond.Kind =3D=3D IrImmediate) { + assert(Res.Kind !=3D IrImmediate); + const TcgV MTrue =3D TE.materialize(True); + const TcgV MFalse =3D TE.materialize(False); + TE.genMov(Res, CE.ternary(Cond, MTrue, MFalse)); + } else { + const TcgV Zero =3D TcgV::makeImmediate("0", Res.intSi= ze()); + TcgSizeAdapter ACond(TE, Cond); + TcgSizeAdapter ATrue(TE, True); + TcgSizeAdapter AFalse(TE, False); + if (True.Kind =3D=3D IrImmediate or False.Kind =3D=3D = IrImmediate) { + auto CTrue =3D TE.materialize(ATrue.get(Res.intSiz= e())); + auto CFalse =3D TE.materialize(AFalse.get(Res.intS= ize())); + auto CCond =3D ACond.get(CTrue.intSize()); + + TE.genMovcond(CmpInst::Predicate::ICMP_NE, Res, CC= ond, + Zero, CTrue, CFalse); + } else { + TE.genMovcond(CmpInst::Predicate::ICMP_NE, Res, + ACond.get(Res.intSize()), Zero, + ATrue.get(Res.intSize()), + AFalse.get(Res.intSize())); + } + } + } break; + case Instruction::Ret: { + auto Ret =3D cast(&I); + if (Ret->getNumOperands() =3D=3D 0) { + break; + } + assert(TAD.hasReturnValue()); + const TcgV Tcg =3D TAD.Map.lookup(Ret->getReturnValue()); + // Even if `SkipReturnMov` is set we need to emit a mov for + // constant expressions and immediates. + if (Tcg.Kind =3D=3D IrImmediate or Tcg.ConstantExpression = or + (TAD.flags & SkipReturnMov) =3D=3D 0) { + TE.genMov(TAD.ReturnValue, Tcg); + } + } break; + case Instruction::Load: { + auto *Load =3D cast(&I); + auto *LlvmPtr =3D Load->getPointerOperand(); + const TcgV Ptr =3D Mapper.defineValue(LlvmPtr); + const TcgV Res =3D Mapper.defineValue(Load); + + switch (Ptr.Kind) { + case IrPtr: { + auto Zero =3D TcgV::makeImmediate("0", Res.intSize()); + TE.genHostLoad(Res, Ptr, Zero); + } break; + case IrImmediate: { + // Add pointer dereference to immediate address + TE.genMov(Res, CE.deref(Ptr, Res.intSize())); + } break; + case IrValue: { + TE.genMov(Res, Ptr); + } break; + case IrPtrToOffset: { + TE.genHostLoadFromVec(Res, Ptr); + } break; + default: + return mkError("Load from unsupported TcgV type"); + }; + } break; + case Instruction::Store: { + auto *Store =3D cast(&I); + auto *LlvmPtr =3D Store->getPointerOperand(); + const TcgV Val =3D Mapper.defineValue(Store->getValueOpera= nd()); + const TcgV Ptr =3D Mapper.defineValue(LlvmPtr); + if (Ptr.Kind =3D=3D IrValue) { + // TODO: Is this path still needed? + switch (Val.Kind) { + case IrImmediate: + case IrValue: { + TE.genMov(Ptr, Val); + } break; + default: + return mkError("Store from unsupported TcgV type"); + }; + } else if (Ptr.Kind =3D=3D IrPtr) { + TE.genHostStore(Ptr, TE.materialize(Val)); + } else if (Ptr.Kind =3D=3D IrPtrToOffset) { + // Stores to IrPtrToOffset are ignored, they are an ar= tifact + // of IrPtrToOffset arguments being pointers. Stores to + // results are instead taken care of by whatever instr= uction + // generated the result. + // TODO: This is no longer true, double check + } else { + return mkError("Store to unsupported TcgV kind: ", Sto= re); + } + } break; + case Instruction::Unreachable: { + // TODO: Need to make sure unreachables are optimized out + // earlier. + } break; + case Instruction::Switch: { + auto Switch =3D cast(&I); + // Operands to switch instructions alternate between + // case values and the corresponding label: + // Operands: { Cond, DefaultLabel, Case0, Label0, Case1, + // Label1, ... } + const TcgV Val =3D Mapper.defineValue(Switch->getOperand(0= )); + const TcgV Default =3D + Mapper.mapTcgLabel(cast(Switch->getOperand= (1))); + for (uint32_t i =3D 2; i < Switch->getNumOperands(); i += =3D 2) { + const TcgV BranchVal =3D + Mapper.defineValue(Switch->getOperand(i)); + const TcgV Branch =3D Mapper.mapTcgLabel( + cast(Switch->getOperand(i + 1))); + TE.genBrcond(CmpInst::Predicate::ICMP_EQ, Val, BranchV= al, + Branch); + } + TE.genBr(Default); + } break; + default: { + return mkError("Instruction not yet implemented: ", &I); + } + } + } + } + + return Error::success(); +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381114; cv=none; d=zohomail.com; s=zohoarc; b=TTBC/QA06dMvzXtSF8ZS3b/7rF1t4Uw8yztA6F47Mfwt8gg4QYLJfWBlOMW9PPhA2CxapARY9QptiQXGBY4S8CGA2Iz4QeZBreIEzB9n8q6lH5IEVKE/A5c4fJ4V6EnkZ59dAD3lbbNtpMMHYTp18kF54k7wvFCN8BIUKHuoy5A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381114; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=2nx+siy0n15hnIPg84YJx5dCMoF7ImJ6zLwFTxBFhXM=; b=HuOO3BUSzXLpJ9mykkMkX9kfH+X0t6BYp6rPhuiFrQJ+MOWD7D/wTnX7KllBzU9IP38kyfkzbxQNzHJhgR+2gXklaW/jOTnKQpNq5UVOyU4rPHyUV2x9orVxNO7ieXtxpU2F6M/kGR2p4E2D1n1krVYOqavN8Emxn2RdKBTbRH8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381114247568.8277900209904; Wed, 29 Jul 2026 20:11:54 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7h-0005QF-00; Wed, 29 Jul 2026 23:07:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7G-0004gV-Dj for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:27 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7C-00030K-6r for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:26 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=2nx+siy0n15hnIPg84YJx5dCMoF7ImJ6zLwFTxBFhXM=; b=UfCkbnjymIsfib0 tWaoIa7rpi30sgwEjR+CGeRMzAhkIEY0ilXOkR4hw1jYNbUsFGmc9OcFmWd8Z4CikMwYDrIYzCFhk WfNWo/M59DqFG6EeYYFJkWOYELAJp3A4QAxrAs46vme4QMiumVfntu/YcaBO0PdfogN+ZQBFJqx37 dY=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 38/50] helper-to-tcg: Add README Date: Thu, 30 Jul 2026 05:10:12 +0200 Message-ID: <20260730031025.12926-39-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381116150158500 Content-Type: text/plain; charset="utf-8" Signed-off-by: Anton Johansson --- subprojects/helper-to-tcg/README.md | 297 ++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 subprojects/helper-to-tcg/README.md diff --git a/subprojects/helper-to-tcg/README.md b/subprojects/helper-to-tc= g/README.md new file mode 100644 index 0000000000..49654eb79f --- /dev/null +++ b/subprojects/helper-to-tcg/README.md @@ -0,0 +1,297 @@ +# helper-to-tcg + +`helper-to-tcg` is a standalone LLVM IR to TCG translator, with the goal o= f simplifying the implementation of complicated instructions in TCG. Instru= ction semantics can be specified either directly in LLVM IR or any language= that can be compiled to it (C, C++, ...). However, the tool is tailored to= wards QEMU helper functions written in C. + +Internally, `helper-to-tcg` consists of a mix of custom and built-in trans= formation and analysis passes that are applied to the input LLVM IR sequent= ially. The pipeline of passes is laid out as follows +``` + +---------------+ +-----+ +---------------+ +---------= ---+ +LLVM IR -> | PrepareForOpt | -> | -Oz | -> | PrepareForTcg | -> | TcgGenPa= ss | -> TCG + +---------------+ +-----+ +---------------+ +---------= ---+ +``` +where the custom passes performs: +* `PrepareForOpt` - Early information gathering and culling pass. Removes = unneeded functions, maps function annotations, gathers debuginfo data, dema= ngles function names, etc.; +* `PrepareForTcg` - Post-optimization pass that tries to get the IR as clo= se to TCG as possible, goal is to take complexity away from the backend; +* `TcgGenPass` - Backend pass that propagates constants, allocates TCG var= iables to LLVM values, and emits final TCG C code. + +As for LLVM optimization, `-Oz` strikes a good balance between unrolling a= nd vectorization, from testing. More aggressive optimization levels would o= ften unroll loops over compacting it with loop vectorization. + +## Project Structure + +* `get-llvm-ir.py` - Helper script to convert a QEMU `.c` file to LLVM IR = by getting compile flags from `compile_commands.json`; +* `pipeline` - Implementation of a LLVM pipeline orchestrating passes and = handling input; +* `src` - Implementation of custom LLVM passes: `PrepareForOptPass`,`Prepa= reForTcgPass`,`TcgGenPass`, and common features; +* `include` - Shared headers between `src`; +* `tests` - Simple end-to-end tests of C functions we expect to be able to= translate, tests fail if any function fails to translate, output is verifi= ed against expected output for support major LLVM versions. + +## Example Translations + +`helper-to-tcg` is able to deal with a wide variety of helper functions, t= he following code snippet contains two examples from the Hexagon architectu= re implementing the semantics of a predicated and instruction (`A2_pandt`) = and a vectorized signed saturated 2-element scalar product (`V6_vdmpyhvsat`= ). + +```c +int32_t HELPER(A2_pandt)(CPUHexagonState *env, int32_t RdV, + int32_t PuV, int32_t RsV, int32_t RtV) +{ + if(fLSBOLD(PuV)) { + RdV=3DRsV&RtV; + } else { + CANCEL; + } + return RdV; +} + +void HELPER(V6_vdmpyhvsat)(CPUHexagonState *env, + void * restrict VdV_void, + void * restrict VuV_void, + void * restrict VvV_void) +{ + fVFOREACH(32, i) { + size8s_t accum =3D fMPY16SS(fGETHALF(0,VuV.w[i]),fGETHALF(0, VvV.w= [i])); + accum +=3D fMPY16SS(fGETHALF(1,VuV.w[i]),fGETHALF(1, VvV.w[i])); + VdV.w[i] =3D fVSATW(accum); + } +} +``` +For the above snippet, `helper-to-tcg` produces the following TCG +```c +void emit_A2_pandt(TCGv_i32 temp0, TCGv_env env, TCGv_i32 temp4, + TCGv_i32 temp8, TCGv_i32 temp7, TCGv_i32 temp6) { + TCGv_i32 temp2 =3D tcg_temp_new_i32(); + tcg_gen_andi_i32(temp2, temp8, 1); + TCGv_i32 temp5 =3D tcg_temp_new_i32(); + tcg_gen_and_i32(temp5, temp6, temp7); + tcg_gen_movcond_i32(TCG_COND_EQ, temp0, temp2, tcg_constant_i32(0), te= mp4, temp5); +} + +void emit_V6_vdmpyhvsat(TCGv_env env, intptr_t vec3, + intptr_t vec7, intptr_t vec6) { + VectorMem mem =3D {0}; + intptr_t vec0 =3D temp_new_gvec(&mem, 128); + tcg_gen_gvec_shli(MO_32, vec0, vec7, 16, 128, 128); + intptr_t vec5 =3D temp_new_gvec(&mem, 128); + tcg_gen_gvec_sari(MO_32, vec5, vec0, 16, 128, 128); + intptr_t vec1 =3D temp_new_gvec(&mem, 128); + tcg_gen_gvec_shli(MO_32, vec1, vec6, 16, 128, 128); + tcg_gen_gvec_sari(MO_32, vec1, vec1, 16, 128, 128); + tcg_gen_gvec_mul(MO_32, vec1, vec1, vec5, 128, 128); + intptr_t vec2 =3D temp_new_gvec(&mem, 128); + tcg_gen_gvec_sari(MO_32, vec2, vec7, 16, 128, 128); + tcg_gen_gvec_sari(MO_32, vec0, vec6, 16, 128, 128); + tcg_gen_gvec_mul(MO_32, vec2, vec0, vec2, 128, 128); + tcg_gen_gvec_ssadd(MO_32, vec3, vec1, vec2, 128, 128); +} +``` + +In the first case, the predicated and instruction was made branchless by u= sing a conditional move, and in the latter case the inner loop of the vecto= rized scalar product could be converted to a few vectorized shifts and mult= iplications, folllowed by a vectorized signed saturated addition. + +## Usage + +Building `helper-to-tcg` produces a binary implementing the pipeline outli= ned above, going from LLVM IR to TCG. + +### Specifying Functions to Translate + +Unless `--translate-all-helpers` is specified, the default behaviour of `h= elper-to-tcg` is to only translate functions annotated via a special `"help= er-to-tcg"` annotation. Functions called by annotated functions will also b= e translated, see the following example: + +```c +// Function will be translated, annotation provided +__attribute__((annotate ("helper-to-tcg"))) +int f(int a, int b) { + return 2 * g(a, b); +} + +// Function will be translated, called by annotated `f()` function +int g(int a, int b) { + ... +} + +// Function will not be translated +int h(int a, int b) { + ... +} +``` + +### Immediate and Vector Arguments + +Function annotations are in some cases used to provide extra information t= o `helper-to-tcg` not otherwise present in the IR. For example, whether an = integer argument should actually be treated as an immediate rather than a r= egister, or if a pointer argument should be treated as a `gvec` vector (off= set into `CPUArchState`). For instance: +```c +__attribute__((annotate ("helper-to-tcg"))) +__attribute__((annotate ("immediate: 1"))) +int f(int a, int i) { + ... +} + +__attribute__((annotate ("helper-to-tcg"))) +__attribute__((annotate ("ptr-to-offset: 0, 1"))) +void g(void * restrict a, void * restrict b) { + ... +} +``` +where `"immediate: 1"` tells `helper-to-tcg` that the argument with index = `1` should be treated as an immediate (multiple arguments are specified thr= ough a comma separated list). Similarly `"ptr-to-offset: 0, 1"` indicates t= hat arguments width index 0 and 1 should be treated as offsets from `CPUArc= hState` (given as `intptr_t`), rather than actual pointer arguments. For th= e above code, `helper-to-tcg` emits +```c +void emit_f(TCGv_i32 res, TCGv_i32 a, int i) { + ... +} + +void emit_g(intptr_t a, intptr_t b) { + ... +} +``` + +### Loads and Stores + +Translating loads and stores is slightly trickier, as some QEMU specific a= ssumptions are made. Loads and stores in the input are assumed to go throug= h the `cpu_[st|ld]*()` functions defined in `exec/cpu_ldst.h` that a helper= function would use.=20 + +If using standalone input functions (not QEMU helper functions), loads and= stores are still represented by `cpu_[st|ld]*()` which needs to be declare= d, consider: +```c +/* Opaque CPU state type, will be mapped to tcg_env */ +struct CPUArchState; +typedef struct CPUArchState CPUArchState; + +/* Prototype of QEMU helper guest load/store functions, see exec/cpu_ldst.= h */ +uint32_t cpu_ldub_data(CPUArchState *, uint32_t ptr); +void cpu_stb_data(CPUArchState *, uint32_t ptr, uint32_t data); + +uint32_t helper_ld8(CPUArchState *env, uint32_t addr) { + return cpu_ldub_data(env, addr); +} + +void helper_st8(CPUArchState *env, uint32_t addr, uint32_t data) { + return cpu_stb_data(env, addr, data); +} +``` +implementing an 8-bit load and store instruction, these will be translated= to the following TCG. +```c +void emit_ld8(TCGv_i32 temp0, TCGv_env env, TCGv_i32 temp1) { + tcg_gen_qemu_ld_i32(temp0, temp1, tb_mmu_index(tcg_ctx->gen_tb->flags)= , MO_UB); +} + +void emit_st8(TCGv_env env, TCGv_i32 temp0, TCGv_i32 temp1) { + tcg_gen_qemu_st_i32(temp1, temp0, tb_mmu_index(tcg_ctx->gen_tb->flags)= , MO_UB); +} +``` +Note, the emitted code assumes the definition of a `tb_mmu_index()` functi= on to retrieve the current CPU MMU index, the name of this function can be = configured via the `--mmu-index-function` flag. + +### Mapping CPU State + +In QEMU, commonly accessed fields in the `CPUArchState` are often mapped t= o global `TCGv*` variables representing that piece of CPU state in TCG. Whe= n translating helper functions (or other C functions), a method of specifyi= ng which fields in the CPU state should be mapped to which globals is neede= d. To this end, a declarative approach is taken, where mappings between CPU= state and globals can be consumed by both `helper-to-tcg` and runtime QEMU= for instantiating the `TCGv` globals themselves. + +Users must define this mapping via a global `cpu_tcg_mapping []` array, as= can be seen in the following example where `mapped_field` of `CPUArchState= ` is mapped to the global `tcg_field`. For more complicated examples see th= e tests in `tests/cpustate.c`. +```c +#include +#include "tcg/tcg-global-mappings.h" + +/* Define a CPU state with some different fields */ + +typedef struct CPUArchState { + uint32_t mapped_field; + uint32_t unmapped_field; +} CPUArchState; + +/* Dummy struct, in QEMU this would correspond to TCGv_i32 in tcg.h */ +typedef struct TCGv_i32 {} TCGv_i32; + +/* Global TCGv representing CPU state */ +TCGv_i32 tcg_field; + +/* + * Finally provide a mapping of CPUArchState to TCG globals we care about,= here + * we map mapped_field to tcg_field + */ +cpu_tcg_mapping mappings[] =3D { + CPU_TCG_MAP(CPUArchState, tcg_field, mapped_field), +}; + +uint32_t helper_mapped(CPUArchState *env) { + return env->mapped_field; +} + +uint32_t helper_unmapped(CPUArchState *env) { + return env->unmapped_field; +} +``` +Note, the name of the `cpu_tcg_mapping[]` is provided via the `--tcg-globa= l-mappings` flag. For the above example, `helper-to-tcg` emits +```c +extern TCGv_i32 tcg_field; + +void emit_mapped(TCGv_i32 temp0, TCGv_env env) { + tcg_gen_mov_i32(temp0, tcg_field); +} + +void emit_unmapped(TCGv_i32 temp0, TCGv_env env) { + TCGv_ptr ptr1 =3D tcg_temp_new_ptr(); + tcg_gen_addi_ptr(ptr1, env, 128ull); + tcg_gen_ld_i32(temp0, ptr1, 0); +} +``` +where accesses in the input C code are correctly mapped to the correspondi= ng TCG globals. The unmapped `CPUArchState` access turns into pointer math = and a load, whereas the mapped access turns into a `mov` from a global. + +### Automatic Calling of Generated Code + +Finally, calling the generated code is as simple as including the output o= f `helper-to-tcg` into the project and manually calling `emit_*(...)`. Howe= ver, when dealing with an existing frontend that has a lot of helper functi= ons already in use, we simplify this process somewhat for non-vector instru= ctions. For translated helper functions `helper-to-tcg` emits its own `gen_= helper_*()` function definitions +```c +/* helper-to-tcg-emitted.c */ +void emit_add(TCGv_ptr env, TCGv_i32 d, TCGv_i32 a, uint32_t imm) +{ + tcg_gen_addi_i32(d, a, imm); +} + +/* helper-to-tcg-emitted.h */ +static inline void gen_helper_add_imm(TCGv_ptr env, TCGv_i32 d, TCGv_i32 a= , TCGv_i32 imm) +{ + emit_add(env, d, a, tcgv_i32_temp(imm)->val); +} +``` +then from code that needs to call `gen_helper_add_imm` include +```c +/* translate.c */ + +/* + * Include generated gen_helper_*() definitions if using helper-to-tcg, but + * only when not generating input IR since the header won't exist at that = point. + */ +#if defined(TARGET_HELPER_TO_TCG) && !defined(HELPER_TO_TCG_IR_GEN) +#include "helper-to-tcg-emitted.h" +#else +#include "exec/helper-gen.h" +#endif +``` + +### Simple Command Usage + +Assume a `helpers.c` file with functions to translate, then to obtain LLVM= IR +```bash +$ clang helpers.c -O0 -Xclang -disable-O0-optnone -S -emit-llvm +``` +which produces `helpers.ll` to be fed into `helper-to-tcg` +```bash +$ ./helper-to-tcg helpers.ll --translate-all-helpers +``` +where `--translate-all-helpers` means "translate all functions starting wi= th helper_*". Finally, the above command produces `helper-to-tcg-emitted.[c= |h]` with emitted TCG code. + +By default meson uses `llvm-config` to find LLVM, usually this corresponds= to the latest version installed on the system. Since `helper-to-tcg` only = supports LLVM 15-21, the path to `llvm-config` can be manually overridden u= sing `meson configure -Dllvm_config_path=3D...` when needed. This is also u= seful for testing multiple LLVM versions. If `helper-to-tcg` is used as a p= art of `QEMU`, this is specified using `../configure -Dhelper_to_tcg:llvm_c= onfig_path=3D...`. + +### Testing + +When building `helper-to-tcg` as a part of a QEMU project the `end-to-end`= tests may be ran via either of the commands +```bash +$ make check +$ make check-helper-to-tcg +$ meson test --suite 'helper-to-tcg:end-to-end' +``` +where the last one is useful when building as a standalone project. + +On the QEMU end, a docker container has been added for testing with the su= pported LLVM versions, this may be triggered via +```bash +$ make docker-test-helper-to-tcg@debian-llvm +``` +and will build `helper-to-tcg` along with the current target, run all end-= to-end and `check-tcg` tests for each version of LLVM that is targeted. + +Debug logging can be turned on via +```bash +$ ./helper-to-tcg --debug +``` +or to restrict logging to given pass + +```bash +$ ./helper-to-tcg --debug-only=3D${pass} +``` +where `${pass}` is one of `map-tcg-ops, map-temporaries, map-arguments, tc= g-gen-pass, pipeline, transform-geps, prepare-for-opt`. --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381114; cv=none; d=zohomail.com; s=zohoarc; b=R/5W5xWWJwI4kkMayqVRZfrgvpAKlkukNWvFm5neDP20RFU17le36PTO8P5smNeONVMxpfVN0Y3nAOA+YXFp5b5b+WpubJ+GhMIS+vUToVCWRfe5oYEO/F4BPNG1isKwm/r27Jpl5dbZt16MHLI6JakKxx/+sQ0m2D/w7nPxXHU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381114; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=yLtiDPWrhpHEzs+8I04IWvaSBZQpQvDVHMWqtGD46Jg=; b=M/V3sbPDZ2BYSLcQS+zAaS/j4HLWFh9eH9RrjedUUK8aYP6hLMn3YIFxAn2ZFh5VkODNz0g5DNguMggVPk0fOxUgv4zcHHlry9JjbCYpWjnnGk48yTxt8WeYy3QNEBwZldnZ5IWcr23Nh27HI21pySWd0jI+SgCb+/y7guvVuhE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381114510457.9416690360979; Wed, 29 Jul 2026 20:11:54 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7e-0005BL-BG; Wed, 29 Jul 2026 23:07:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7N-0004iP-E1 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:36 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7E-00030W-1i for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:32 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=yLtiDPWrhpHEzs+8I04IWvaSBZQpQvDVHMWqtGD46Jg=; b=eUUEcOmZd5mwIy0 Hq0H/8Bxrf8tqXNHtHPfrO0cP2r5u/bKhFC5Dns3RQDGZhH+98r6WuBP74CeuURW6/5VJcQQP9mmj GnyITRZ3DD39z3fDNxJ/HojTEpSJuMZln+5eQ6RA24/m1DhvaESwYqVAdIaWg7G67mdkLX0k2QAWh rA=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 39/50] helper-to-tcg: Add end-to-end tests Date: Thu, 30 Jul 2026 05:10:13 +0200 Message-ID: <20260730031025.12926-40-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381116336158500 Content-Type: text/plain; charset="utf-8" Introduces simple end-to-end tests, providing input functions covering a variety of features, and expected outputs for each of test and supported LLVM version. (Currently reference code for LLVM 15 and 21 is added). Signed-off-by: Anton Johansson --- subprojects/helper-to-tcg/meson.build | 2 + .../helper-to-tcg/tests/call-to-declaration.c | 33 ++ .../helper-to-tcg/tests/call-translation.c | 35 ++ subprojects/helper-to-tcg/tests/cpustate.c | 44 ++ .../helper-to-tcg/tests/forward-context.c | 21 + subprojects/helper-to-tcg/tests/ldst.c | 17 + subprojects/helper-to-tcg/tests/meson.build | 121 ++++ .../tests/ref/15/call-to-declaration.c | 26 + .../tests/ref/15/call-translation.c | 28 + .../helper-to-tcg/tests/ref/15/cpustate.c | 36 ++ .../tests/ref/15/forward-context.c | 30 + subprojects/helper-to-tcg/tests/ref/15/ldst.c | 21 + .../helper-to-tcg/tests/ref/15/scalar.c | 21 + .../tests/ref/15/user-pcrel-jump.c | 33 ++ .../tests/ref/15/vector-layout-f16L.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-f16M.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-f32L.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-f32M.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-f64L.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-f64M.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-f8L.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-f8M.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-t16L.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-t16M.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-t32L.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-t32M.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-t64L.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-t64M.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-t8L.c | 527 ++++++++++++++++++ .../tests/ref/15/vector-layout-t8M.c | 527 ++++++++++++++++++ .../helper-to-tcg/tests/ref/15/vector.c | 31 ++ .../tests/ref/21/call-to-declaration.c | 26 + .../tests/ref/21/call-translation.c | 28 + .../helper-to-tcg/tests/ref/21/cpustate.c | 36 ++ .../tests/ref/21/forward-context.c | 30 + subprojects/helper-to-tcg/tests/ref/21/ldst.c | 21 + .../helper-to-tcg/tests/ref/21/scalar.c | 21 + .../tests/ref/21/user-pcrel-jump.c | 33 ++ .../tests/ref/21/vector-layout-f16L.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-f16M.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-f32L.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-f32M.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-f64L.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-f64M.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-f8L.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-f8M.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-t16L.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-t16M.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-t32L.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-t32M.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-t64L.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-t64M.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-t8L.c | 527 ++++++++++++++++++ .../tests/ref/21/vector-layout-t8M.c | 527 ++++++++++++++++++ .../helper-to-tcg/tests/ref/21/vector.c | 31 ++ subprojects/helper-to-tcg/tests/scalar.c | 15 + .../helper-to-tcg/tests/tcg-global-mappings.h | 118 ++++ .../helper-to-tcg/tests/user-pcrel-jump.c | 28 + .../helper-to-tcg/tests/vector-layout.c | 51 ++ subprojects/helper-to-tcg/tests/vector.c | 34 ++ 60 files changed, 17835 insertions(+) create mode 100644 subprojects/helper-to-tcg/tests/call-to-declaration.c create mode 100644 subprojects/helper-to-tcg/tests/call-translation.c create mode 100644 subprojects/helper-to-tcg/tests/cpustate.c create mode 100644 subprojects/helper-to-tcg/tests/forward-context.c create mode 100644 subprojects/helper-to-tcg/tests/ldst.c create mode 100644 subprojects/helper-to-tcg/tests/meson.build create mode 100644 subprojects/helper-to-tcg/tests/ref/15/call-to-declarat= ion.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/call-translation= .c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/cpustate.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/forward-context.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/ldst.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/scalar.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/user-pcrel-jump.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-f1= 6L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-f1= 6M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-f3= 2L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-f3= 2M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-f6= 4L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-f6= 4M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-f8= L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-f8= M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-t1= 6L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-t1= 6M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-t3= 2L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-t3= 2M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-t6= 4L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-t6= 4M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-t8= L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector-layout-t8= M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/15/vector.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/call-to-declarat= ion.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/call-translation= .c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/cpustate.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/forward-context.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/ldst.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/scalar.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/user-pcrel-jump.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-f1= 6L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-f1= 6M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-f3= 2L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-f3= 2M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-f6= 4L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-f6= 4M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-f8= L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-f8= M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-t1= 6L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-t1= 6M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-t3= 2L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-t3= 2M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-t6= 4L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-t6= 4M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-t8= L.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector-layout-t8= M.c create mode 100644 subprojects/helper-to-tcg/tests/ref/21/vector.c create mode 100644 subprojects/helper-to-tcg/tests/scalar.c create mode 100644 subprojects/helper-to-tcg/tests/tcg-global-mappings.h create mode 100644 subprojects/helper-to-tcg/tests/user-pcrel-jump.c create mode 100644 subprojects/helper-to-tcg/tests/vector-layout.c create mode 100644 subprojects/helper-to-tcg/tests/vector.c diff --git a/subprojects/helper-to-tcg/meson.build b/subprojects/helper-to-= tcg/meson.build index 413d7ad8fa..d903b560d1 100644 --- a/subprojects/helper-to-tcg/meson.build +++ b/subprojects/helper-to-tcg/meson.build @@ -82,3 +82,5 @@ pipeline =3D executable('helper-to-tcg', sources, include_directories: ['include'] + [incdir], link_args: [ldflags] + [libs] + [syslibs], cpp_args: cpp_args) + +subdir('tests') diff --git a/subprojects/helper-to-tcg/tests/call-to-declaration.c b/subpro= jects/helper-to-tcg/tests/call-to-declaration.c new file mode 100644 index 0000000000..d0fc583270 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/call-to-declaration.c @@ -0,0 +1,33 @@ +/* + * Test translation of calls to declration + * + * (experimental) + */ + +#define ANNOTATE(str) __attribute__((annotate(str))) + +int fdecl0(int a); + +ANNOTATE("helper-to-tcg") +int f0(int cond, int b) { + return fdecl0(b); +} + +ANNOTATE("immediate: 0") +int fdecl1(int a); + +ANNOTATE("helper-to-tcg") +ANNOTATE("immediate: 1") +int f1(int cond, int b) { + return fdecl1(b); +} + +ANNOTATE("returns-immediate") +ANNOTATE("immediate: 0") +int fdecl2(int a); + +ANNOTATE("helper-to-tcg") +ANNOTATE("immediate: 0") +int f2(int b) { + return fdecl2(b); +} diff --git a/subprojects/helper-to-tcg/tests/call-translation.c b/subprojec= ts/helper-to-tcg/tests/call-translation.c new file mode 100644 index 0000000000..fc3ca68755 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/call-translation.c @@ -0,0 +1,35 @@ +/* + * Test translation of dependent functions. + * + * This test will be ran without --translate-all-helpers, meaning we have = to + * manually mark them for translation. + */ + +#define ANNOTATE(str) __attribute__((annotate(str))) + +/* + * Only inner0 is marked for translation, outer0 will be skipped. + */ +ANNOTATE("helper-to-tcg") +int inner0(int a) { return a + 5; } + +int outer0(int cond, int b) { + if (cond) { + return inner0(b); + } + return 0; +} + +/* + * Both inner1 and outer1 will be translated since outer1 is marked for + * translation and depends on inner1. + */ +int inner1(int a) { return a + 5; } + +ANNOTATE("helper-to-tcg") +int outer1(int cond, int b) { + if (cond) { + return inner1(b); + } + return 0; +} diff --git a/subprojects/helper-to-tcg/tests/cpustate.c b/subprojects/helpe= r-to-tcg/tests/cpustate.c new file mode 100644 index 0000000000..61ff6b28cf --- /dev/null +++ b/subprojects/helper-to-tcg/tests/cpustate.c @@ -0,0 +1,44 @@ +#include +#include + +#define stringify(str) #str + +#include "tcg-global-mappings.h" + +typedef struct SpecialData { + uint32_t a; + uint32_t unmapped_field; +} SpecialData; + +typedef struct CPUArchState { + uint32_t regs[32]; + uint32_t unmapped_field; + SpecialData data[8]; + uint32_t mapped_field; +} CPUArchState; + +/* Dummy struct, in QEMU this would correspond to TCGv_i32 in tcg.h */ +/* Global TCGv's representing CPU state */ +struct{} tcg_regs[32]; +struct{} tcg_a[8]; +struct{} tcg_field; + +cpu_tcg_mapping mappings[] =3D { + CPU_TCG_MAP_ARRAY(CPUArchState, tcg_regs, regs, NULL), + CPU_TCG_MAP_ARRAY_OF_STRUCTS(CPUArchState, tcg_a, data, a, NULL), + CPU_TCG_MAP(CPUArchState, tcg_field, mapped_field), +}; + +__attribute__((annotate("immediate: 1"))) uint32_t helper_reg(CPUArchState= *env, + uint32_t i) { + return env->regs[i]; +} + +__attribute__((annotate("immediate: 1"))) uint32_t +helper_data_a(CPUArchState *env, uint32_t i) { + return env->data[i].a; +} + +uint32_t helper_single_mapped(CPUArchState *env) { return env->mapped_fiel= d; } + +uint32_t helper_unmapped(CPUArchState *env) { return env->unmapped_field; } diff --git a/subprojects/helper-to-tcg/tests/forward-context.c b/subproject= s/helper-to-tcg/tests/forward-context.c new file mode 100644 index 0000000000..4eb55b7e3d --- /dev/null +++ b/subprojects/helper-to-tcg/tests/forward-context.c @@ -0,0 +1,21 @@ +/* + * Test translation of calls to declration + * + * This test will be ran without --translate-all-helpers, meaning we have = to + * manually mark them for translation. + */ + +#define ANNOTATE(str) __attribute__((annotate(str))) + +ANNOTATE("immediate: 0") +int fdecl0(int a); + +ANNOTATE("helper-to-tcg") +int f0(int a, int off) { + return a + fdecl0(off); +} + +ANNOTATE("helper-to-tcg") +int f1(int a) { + return f0(a,a) + f0(-a,-a); +} diff --git a/subprojects/helper-to-tcg/tests/ldst.c b/subprojects/helper-to= -tcg/tests/ldst.c new file mode 100644 index 0000000000..44d32d0875 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ldst.c @@ -0,0 +1,17 @@ +#include + +/* Opaque CPU state type, will be mapped to tcg_env */ +struct CPUArchState; +typedef struct CPUArchState CPUArchState; + +/* Prototype of QEMU helper guest load/store functions, see exec/cpu_ldst.= h */ +uint32_t cpu_ldub_data(CPUArchState *, uint32_t ptr); +void cpu_stb_data(CPUArchState *, uint32_t ptr, uint32_t data); + +uint32_t helper_ld8(CPUArchState *env, uint32_t addr) { + return cpu_ldub_data(env, addr); +} + +void helper_st8(CPUArchState *env, uint32_t addr, uint32_t data) { + return cpu_stb_data(env, addr, data); +} diff --git a/subprojects/helper-to-tcg/tests/meson.build b/subprojects/help= er-to-tcg/tests/meson.build new file mode 100644 index 0000000000..b2e53550eb --- /dev/null +++ b/subprojects/helper-to-tcg/tests/meson.build @@ -0,0 +1,121 @@ +fs =3D import('fs') + +sources =3D { + 'scalar.c' : ['--translate-all-helpers'], + 'ldst.c' : [ + '--translate-all-helpers', + '--mmu-index-function=3Dtb_mmu_index', + ], + 'cpustate.c' : [ + '--translate-all-helpers', + '--tcg-global-mappings=3Dmappings', + ], + 'vector.c' : [ + '--translate-all-helpers', + '--temp-vector-block=3Dvmem', + ], + 'call-translation.c' : [], + 'call-to-declaration.c' : [ + '--allow-decl-call', + ], + 'forward-context.c' : [ + '--allow-decl-call', + '--forward-context', + ], + 'user-pcrel-jump.c' : [ + '--allow-decl-call', + '--user-pcrel-branch-func=3Dtarget_pcrel_jump', + '--user-pcrel-branch-conditional-func=3Dtarget_pcrel_jump_cond', + '--user-pcrel-branch-fallthrough-func=3Dtarget_pcrel_jump_fall', + ], +} + +sources_vector_layout =3D { + 'vector-layout.c' : [], +} + +diff =3D find_program('diff') + +foreach file : sources.keys() + extra_flags =3D sources.get(file) + + name =3D file.split('.')[0] + name_ll =3D name + '.ll' + + ll =3D custom_target(name_ll, + input: files(file), + output: name_ll, + command: [clang, '-O0', '-Xclang', '-disable-O0-optnone', + '-g', '-S', '-emit-llvm', '-o', '@OUTPUT@', '@INPUT@'] + ) + + output_prefix =3D join_paths(meson.current_build_dir(), name) + flags =3D [ll, + '--output-enabled=3D' + output_prefix + '-enabled', + '--output-source=3D' + output_prefix + '.c', + '--output-header=3D' + output_prefix + '.h', + '--mmu-index-function=3Dtb_mmu_index', + '--tcg-global-mappings=3Dmappings'] + flags +=3D extra_flags + + runtest =3D name + '-run-' + version_major.to_string() + test(runtest, + pipeline, + depends: ll, + priority: 2, + args: flags, + suite: 'helper-to-tcg') + + ref =3D join_paths(meson.current_source_dir(), 'ref', version_major.to= _string(), name + '.c') + if fs.exists(ref) + test(name + '-diff-' + version_major.to_string(), + diff, + priority: 1, + args: ['-u', output_prefix + '.c', ref ], suite: 'helper-to-tc= g') + endif +endforeach + +# Build and compare tests against references again, but force different ve= ctor layouts. +foreach file : sources_vector_layout.keys() + extra_flags =3D sources_vector_layout.get(file) + name =3D file.split('.')[0] + name_ll =3D name + '.ll' + + ll =3D custom_target(name_ll, + input: files(file), + output: name_ll, + command: [clang, '-O0', '-Xclang', '-disable-O0-optnone', + '-g', '-S', '-emit-llvm', '-o', '@OUTPUT@', '@INPUT@'] + ) + + foreach size : [8,16,32,64] + foreach lane0 : ['LeastSignificant', 'MostSignificant'] + foreach big_endian: ['true', 'false'] + test_str =3D big_endian[0] + size.to_string() + lane0[0] + output_prefix =3D join_paths(meson.current_build_dir(), na= me + '-' + test_str) + runtest =3D name + '-run-' + test_str + test(runtest, + pipeline, + depends: ll, + priority: 2, + args: [ll, + '--output-enabled=3D' + output_prefix + '-enabl= ed', + '--output-source=3D' + output_prefix + '.c', + '--output-header=3D' + output_prefix + '.h', + '--translate-all-helpers', + '--vec-force-big-endian=3D' + big_endian, + '--vec-block-bytes=3D' + size.to_string(), + '--vec-lane-0=3D' + lane0, + ] + extra_flags, + suite: 'helper-to-tcg') + ref =3D join_paths(meson.current_source_dir(), 'ref', vers= ion_major.to_string(), name + '-' + test_str + '.c') + if fs.exists(ref) + test(name + '-diff-' + test_str, + diff, + priority: 1, + args: ['-u', output_prefix + '.c', ref ], suite: '= helper-to-tcg') + endif + endforeach + endforeach + endforeach +endforeach diff --git a/subprojects/helper-to-tcg/tests/ref/15/call-to-declaration.c b= /subprojects/helper-to-tcg/tests/ref/15/call-to-declaration.c new file mode 100644 index 0000000000..e778d8785d --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/call-to-declaration.c @@ -0,0 +1,26 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "call-to-declaration.h" + +// i32 f0 +void emit_f0(TCGv_i32 tmp2, TCGv_i32 tmp0, TCGv_i32 b) { +tmp2 =3D fdecl0(b); +} + +// i32 f1 +void emit_f1(TCGv_i32 tmp2, TCGv_i32 tmp0, uint32_t b) { +tmp2 =3D fdecl1(tcg_constant_i32(b)); +} + +// i32 f2 +void emit_f2(TCGv_i32 tmp1, uint32_t b) { +tmp1 =3D fdecl2(tcg_constant_i32(b)); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/call-translation.c b/su= bprojects/helper-to-tcg/tests/ref/15/call-translation.c new file mode 100644 index 0000000000..406f48953e --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/call-translation.c @@ -0,0 +1,28 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "call-translation.h" + +// i32 inner0 +void emit_inner0(TCGv_i32 tmp2, TCGv_i32 a) { +tcg_gen_add_i32(tmp2, a, tcg_constant_i32(5)); +} + +// i32 inner1 +void emit_inner1(TCGv_i32 tmp2, TCGv_i32 a) { +tcg_gen_add_i32(tmp2, a, tcg_constant_i32(5)); +} + +// i32 outer1 +void emit_outer1(TCGv_i32 tmp5, TCGv_i32 cond, TCGv_i32 b) { +TCGv_i32 tmp6 =3D tcg_temp_new_i32(); +tcg_gen_add_i32(tmp6, b, tcg_constant_i32(5)); +tcg_gen_movcond_i32(TCG_COND_EQ, tmp5, cond, tcg_constant_i32(0), tcg_cons= tant_i32(0), tmp6); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/cpustate.c b/subproject= s/helper-to-tcg/tests/ref/15/cpustate.c new file mode 100644 index 0000000000..e022a14d0c --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/cpustate.c @@ -0,0 +1,36 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "cpustate.h" + +extern TCGv_i32 tcg_regs[32]; +extern TCGv_i32 tcg_a[8]; +extern TCGv_i32 tcg_field; +// i32 helper_reg +void emit_reg(TCGv_i32 tmp5, TCGv_ptr env, uint32_t i) { +tcg_gen_mov_i32(tmp5, tcg_regs[((uint64_t) (uint32_t) i)]); +} + +// i32 helper_data_a +void emit_data_a(TCGv_i32 tmp6, TCGv_ptr env, uint32_t i) { +tcg_gen_mov_i32(tmp6, tcg_a[((uint64_t) (uint32_t) i)]); +} + +// i32 helper_single_mapped +void emit_single_mapped(TCGv_i32 tmp4, TCGv_ptr env) { +tcg_gen_mov_i32(tmp4, tcg_field); +} + +// i32 helper_unmapped +void emit_unmapped(TCGv_i32 tmp2, TCGv_ptr env) { +TCGv_ptr ptr3 =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(ptr3, env, 128ull); +tcg_gen_ld_i32(tmp2, ptr3, 0); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/forward-context.c b/sub= projects/helper-to-tcg/tests/ref/15/forward-context.c new file mode 100644 index 0000000000..a1c0e5f37a --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/forward-context.c @@ -0,0 +1,30 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "translate.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "forward-context.h" + +#include "translate.h" +// i32 f0 +void emit_f0(DisasContext *ctx, TCGv_i32 tmp2, TCGv_i32 a, TCGv_i32 off) { +TCGv_i32 tmp3 =3D tcg_temp_new_i32(); +tmp3 =3D fdecl0(ctx, off); +tcg_gen_add_i32(tmp2, tmp3, a); +} + +// i32 f1 +void emit_f1(DisasContext *ctx, TCGv_i32 tmp2, TCGv_i32 a) { +TCGv_i32 tmp4 =3D tcg_temp_new_i32(); +tmp4 =3D fdecl0(ctx, a); +tcg_gen_sub_i32(tmp2, tcg_constant_i32(0), a); +TCGv_i32 tmp3 =3D tcg_temp_new_i32(); +tmp3 =3D fdecl0(ctx, tmp2); +tcg_gen_add_i32(tmp2, tmp3, tmp4); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/ldst.c b/subprojects/he= lper-to-tcg/tests/ref/15/ldst.c new file mode 100644 index 0000000000..5710b0b285 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/ldst.c @@ -0,0 +1,21 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "ldst.h" + +// i32 helper_ld8 +void emit_ld8(TCGv_i32 tmp4, TCGv_ptr env, TCGv_i32 addr) { +tcg_gen_qemu_ld_i32(tmp4, addr, tb_mmu_index(tcg_ctx->gen_tb->flags), MO_8= ); +} + +// void helper_st8 +void emit_st8(TCGv_ptr env, TCGv_i32 addr, TCGv_i32 data) { +tcg_gen_qemu_st_i32(data, addr, tb_mmu_index(tcg_ctx->gen_tb->flags), MO_8= ); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/scalar.c b/subprojects/= helper-to-tcg/tests/ref/15/scalar.c new file mode 100644 index 0000000000..50fe4307c0 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/scalar.c @@ -0,0 +1,21 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "scalar.h" + +// i32 helper_add +void emit_add(TCGv_i32 tmp2, TCGv_i32 a, TCGv_i32 b) { +tcg_gen_add_i32(tmp2, b, a); +} + +// i32 helper_cmov +void emit_cmov(TCGv_i32 tmp5, TCGv_i32 c0, TCGv_i32 c1, TCGv_i32 a, TCGv_i= 32 b) { +tcg_gen_movcond_i32(TCG_COND_LTU, tmp5, c0, c1, a, b); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/user-pcrel-jump.c b/sub= projects/helper-to-tcg/tests/ref/15/user-pcrel-jump.c new file mode 100644 index 0000000000..68e6c5d441 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/user-pcrel-jump.c @@ -0,0 +1,33 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "user-pcrel-jump.h" + +// void prcel_jump +void emit_prcel_jump(TCGv_i32 off) { +TCGv_i32 ea =3D tcg_temp_new_i32(); +tcg_gen_shl_i32(ea, off, tcg_constant_i32(2)); +tcg_gen_or_i32(ea, ea, tcg_constant_i32(3)); +target_pcrel_jump(ea); +} + +// void prcel_condjump +void emit_prcel_condjump(TCGv_i32 cond, TCGv_i32 off) { +TCGLabel * label8 =3D gen_new_label(); +TCGLabel * label9 =3D gen_new_label(); +tcg_gen_brcondi_i32(TCG_COND_EQ, cond, 0, label8); +gen_set_label(label9); +TCGv_i32 ea =3D tcg_temp_new_i32(); +tcg_gen_shl_i32(ea, off, tcg_constant_i32(2)); +tcg_gen_or_i32(ea, ea, tcg_constant_i32(3)); +target_pcrel_jump(ea); +tcg_gen_br(label8); +gen_set_label(label8); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f16L.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-f16L.c new file mode 100644 index 0000000000..146c940bd4 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f16L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f16L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 2; +const size_t ci =3D i % 8; +const size_t bc =3D c % 2; +return 16 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 2; +const size_t ci =3D i % 4; +const size_t bc =3D c % 2; +return 8 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 2; +const size_t ci =3D i % 2; +const size_t bc =3D c % 2; +return 4 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 2; +const size_t ci =3D i % 1; +const size_t bc =3D c % 2; +return 2 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x807060504030201, 0x100F0E0D0C0B0A= 09, 0x1817161514131211, 0x201F1E1D1C1B1A19}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f16M.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-f16M.c new file mode 100644 index 0000000000..76cff20bee --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f16M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f16M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 2; +const size_t ci =3D i % 8; +const size_t bc =3D c % 2; +return 16 * b + 8 * (1 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 2; +const size_t ci =3D i % 4; +const size_t bc =3D c % 2; +return 8 * b + 4 * (1 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 2; +const size_t ci =3D i % 2; +const size_t bc =3D c % 2; +return 4 * b + 2 * (1 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 2; +const size_t ci =3D i % 1; +const size_t bc =3D c % 2; +return 2 * b + 1 * (1 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x90A0B0C0D0E0F10, 0x10203040506070= 8, 0x191A1B1C1D1E1F20, 0x1112131415161718}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f32L.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-f32L.c new file mode 100644 index 0000000000..8515b3488e --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f32L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f32L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 4; +const size_t ci =3D i % 8; +const size_t bc =3D c % 4; +return 32 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 4; +const size_t ci =3D i % 4; +const size_t bc =3D c % 4; +return 16 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 4; +const size_t ci =3D i % 2; +const size_t bc =3D c % 4; +return 8 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 4; +const size_t ci =3D i % 1; +const size_t bc =3D c % 4; +return 4 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x807060504030201, 0x100F0E0D0C0B0A= 09, 0x1817161514131211, 0x201F1E1D1C1B1A19}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f32M.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-f32M.c new file mode 100644 index 0000000000..41067c4c62 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f32M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f32M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 4; +const size_t ci =3D i % 8; +const size_t bc =3D c % 4; +return 32 * b + 8 * (3 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 4; +const size_t ci =3D i % 4; +const size_t bc =3D c % 4; +return 16 * b + 4 * (3 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 4; +const size_t ci =3D i % 2; +const size_t bc =3D c % 4; +return 8 * b + 2 * (3 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 4; +const size_t ci =3D i % 1; +const size_t bc =3D c % 4; +return 4 * b + 1 * (3 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x191A1B1C1D1E1F20, 0x1112131415161= 718, 0x90A0B0C0D0E0F10, 0x102030405060708}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f64L.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-f64L.c new file mode 100644 index 0000000000..d8e660be8b --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f64L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f64L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 8; +const size_t ci =3D i % 8; +const size_t bc =3D c % 8; +return 64 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 8; +const size_t ci =3D i % 4; +const size_t bc =3D c % 8; +return 32 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 8; +const size_t ci =3D i % 2; +const size_t bc =3D c % 8; +return 16 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 8; +const size_t ci =3D i % 1; +const size_t bc =3D c % 8; +return 8 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x807060504030201, 0x100F0E0D0C0B0A= 09, 0x1817161514131211, 0x201F1E1D1C1B1A19}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f64M.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-f64M.c new file mode 100644 index 0000000000..facfe730c1 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f64M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f64M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 8; +const size_t ci =3D i % 8; +const size_t bc =3D c % 8; +return 64 * b + 8 * (7 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 8; +const size_t ci =3D i % 4; +const size_t bc =3D c % 8; +return 32 * b + 4 * (7 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 8; +const size_t ci =3D i % 2; +const size_t bc =3D c % 8; +return 16 * b + 2 * (7 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 8; +const size_t ci =3D i % 1; +const size_t bc =3D c % 8; +return 8 * b + 1 * (7 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x191A1B1C1D1E1F20, 0x1112131415161= 718, 0x90A0B0C0D0E0F10, 0x102030405060708}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f8L.c b/s= ubprojects/helper-to-tcg/tests/ref/15/vector-layout-f8L.c new file mode 100644 index 0000000000..98f4d0a584 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f8L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f8L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 1; +const size_t ci =3D i % 8; +const size_t bc =3D c % 1; +return 8 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 1; +const size_t ci =3D i % 4; +const size_t bc =3D c % 1; +return 4 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 1; +const size_t ci =3D i % 2; +const size_t bc =3D c % 1; +return 2 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 1; +const size_t ci =3D i % 1; +const size_t bc =3D c % 1; +return 1 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x807060504030201, 0x100F0E0D0C0B0A= 09, 0x1817161514131211, 0x201F1E1D1C1B1A19}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f8M.c b/s= ubprojects/helper-to-tcg/tests/ref/15/vector-layout-f8M.c new file mode 100644 index 0000000000..a768efc628 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-f8M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f8M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 1; +const size_t ci =3D i % 8; +const size_t bc =3D c % 1; +return 8 * b + 8 * (0 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 1; +const size_t ci =3D i % 4; +const size_t bc =3D c % 1; +return 4 * b + 4 * (0 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 1; +const size_t ci =3D i % 2; +const size_t bc =3D c % 1; +return 2 * b + 2 * (0 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 1; +const size_t ci =3D i % 1; +const size_t bc =3D c % 1; +return 1 * b + 1 * (0 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x102030405060708, 0x90A0B0C0D0E0F1= 0, 0x1112131415161718, 0x191A1B1C1D1E1F20}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t16L.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-t16L.c new file mode 100644 index 0000000000..ca6944fa92 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t16L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t16L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 2; +const size_t ci =3D i % 8; +const size_t bc =3D c % 2; +return 16 * b + 8 * (1 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 2; +const size_t ci =3D i % 4; +const size_t bc =3D c % 2; +return 8 * b + 4 * (1 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 2; +const size_t ci =3D i % 2; +const size_t bc =3D c % 2; +return 4 * b + 2 * (1 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 2; +const size_t ci =3D i % 1; +const size_t bc =3D c % 2; +return 2 * b + 1 * (1 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x100F0E0D0C0B0A09, 0x8070605040302= 01, 0x201F1E1D1C1B1A19, 0x1817161514131211}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t16M.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-t16M.c new file mode 100644 index 0000000000..a4e0ca054f --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t16M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t16M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 2; +const size_t ci =3D i % 8; +const size_t bc =3D c % 2; +return 16 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 2; +const size_t ci =3D i % 4; +const size_t bc =3D c % 2; +return 8 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 2; +const size_t ci =3D i % 2; +const size_t bc =3D c % 2; +return 4 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 2; +const size_t ci =3D i % 1; +const size_t bc =3D c % 2; +return 2 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x102030405060708, 0x90A0B0C0D0E0F1= 0, 0x1112131415161718, 0x191A1B1C1D1E1F20}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t32L.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-t32L.c new file mode 100644 index 0000000000..b142d9b8ce --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t32L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t32L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 4; +const size_t ci =3D i % 8; +const size_t bc =3D c % 4; +return 32 * b + 8 * (3 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 4; +const size_t ci =3D i % 4; +const size_t bc =3D c % 4; +return 16 * b + 4 * (3 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 4; +const size_t ci =3D i % 2; +const size_t bc =3D c % 4; +return 8 * b + 2 * (3 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 4; +const size_t ci =3D i % 1; +const size_t bc =3D c % 4; +return 4 * b + 1 * (3 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x201F1E1D1C1B1A19, 0x1817161514131= 211, 0x100F0E0D0C0B0A09, 0x807060504030201}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t32M.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-t32M.c new file mode 100644 index 0000000000..109ab19c39 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t32M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t32M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 4; +const size_t ci =3D i % 8; +const size_t bc =3D c % 4; +return 32 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 4; +const size_t ci =3D i % 4; +const size_t bc =3D c % 4; +return 16 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 4; +const size_t ci =3D i % 2; +const size_t bc =3D c % 4; +return 8 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 4; +const size_t ci =3D i % 1; +const size_t bc =3D c % 4; +return 4 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x102030405060708, 0x90A0B0C0D0E0F1= 0, 0x1112131415161718, 0x191A1B1C1D1E1F20}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t64L.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-t64L.c new file mode 100644 index 0000000000..4f325caa75 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t64L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t64L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 8; +const size_t ci =3D i % 8; +const size_t bc =3D c % 8; +return 64 * b + 8 * (7 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 8; +const size_t ci =3D i % 4; +const size_t bc =3D c % 8; +return 32 * b + 4 * (7 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 8; +const size_t ci =3D i % 2; +const size_t bc =3D c % 8; +return 16 * b + 2 * (7 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 8; +const size_t ci =3D i % 1; +const size_t bc =3D c % 8; +return 8 * b + 1 * (7 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x201F1E1D1C1B1A19, 0x1817161514131= 211, 0x100F0E0D0C0B0A09, 0x807060504030201}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t64M.c b/= subprojects/helper-to-tcg/tests/ref/15/vector-layout-t64M.c new file mode 100644 index 0000000000..766a827128 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t64M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t64M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 8; +const size_t ci =3D i % 8; +const size_t bc =3D c % 8; +return 64 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 8; +const size_t ci =3D i % 4; +const size_t bc =3D c % 8; +return 32 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 8; +const size_t ci =3D i % 2; +const size_t bc =3D c % 8; +return 16 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 8; +const size_t ci =3D i % 1; +const size_t bc =3D c % 8; +return 8 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x102030405060708, 0x90A0B0C0D0E0F1= 0, 0x1112131415161718, 0x191A1B1C1D1E1F20}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t8L.c b/s= ubprojects/helper-to-tcg/tests/ref/15/vector-layout-t8L.c new file mode 100644 index 0000000000..18feb85fad --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t8L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t8L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 1; +const size_t ci =3D i % 8; +const size_t bc =3D c % 1; +return 8 * b + 8 * (0 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 1; +const size_t ci =3D i % 4; +const size_t bc =3D c % 1; +return 4 * b + 4 * (0 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 1; +const size_t ci =3D i % 2; +const size_t bc =3D c % 1; +return 2 * b + 2 * (0 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 1; +const size_t ci =3D i % 1; +const size_t bc =3D c % 1; +return 1 * b + 1 * (0 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x807060504030201, 0x100F0E0D0C0B0A= 09, 0x1817161514131211, 0x201F1E1D1C1B1A19}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t8M.c b/s= ubprojects/helper-to-tcg/tests/ref/15/vector-layout-t8M.c new file mode 100644 index 0000000000..97ebe17e91 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector-layout-t8M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t8M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 1; +const size_t ci =3D i % 8; +const size_t bc =3D c % 1; +return 8 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 1; +const size_t ci =3D i % 4; +const size_t bc =3D c % 1; +return 4 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 1; +const size_t ci =3D i % 2; +const size_t bc =3D c % 1; +return 2 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 1; +const size_t ci =3D i % 1; +const size_t bc =3D c % 1; +return 1 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x102030405060708, 0x90A0B0C0D0E0F1= 0, 0x1112131415161718, 0x191A1B1C1D1E1F20}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/15/vector.c b/subprojects/= helper-to-tcg/tests/ref/15/vector.c new file mode 100644 index 0000000000..deeec8e8ab --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/15/vector.c @@ -0,0 +1,31 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector.h" + +// void helper_vec_splat_reg +void emit_vec_splat_reg(intptr_t d, TCGv_i32 imm) { +tcg_gen_gvec_dup_i32(MO_8, d, 32ull, 32ull, imm); +} + +// void helper_vec_splat_imm +void emit_vec_splat_imm(intptr_t d, uint8_t imm) { +tcg_gen_gvec_dup_imm(MO_8, d, 32ull, 32ull, imm); +} + +// void helper_vec_add +void emit_vec_add(intptr_t d, intptr_t a, intptr_t b) { +tcg_gen_gvec_add(MO_8, d, b, a, 32, 32); +} + +// void helper_vec_add32 +void emit_vec_add32(intptr_t d, intptr_t a, intptr_t b) { +tcg_gen_gvec_add(MO_32, d, b, a, 128, 128); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/call-to-declaration.c b= /subprojects/helper-to-tcg/tests/ref/21/call-to-declaration.c new file mode 100644 index 0000000000..4b445ec8b1 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/call-to-declaration.c @@ -0,0 +1,26 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "call-to-declaration.h" + +// i32 f0 +void emit_f0(TCGv_i32 tmp2, TCGv_i32 tmp0, TCGv_i32 b) { +tmp2 =3D fdecl0(b); +} + +// i32 f1 +void emit_f1(TCGv_i32 tmp2, TCGv_i32 tmp0, uint32_t b) { +tmp2 =3D fdecl1(b); +} + +// i32 f2 +void emit_f2(TCGv_i32 tmp2, uint32_t b) { +tcg_gen_movi_i32(tmp2, imm1); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/call-translation.c b/su= bprojects/helper-to-tcg/tests/ref/21/call-translation.c new file mode 100644 index 0000000000..406f48953e --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/call-translation.c @@ -0,0 +1,28 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "call-translation.h" + +// i32 inner0 +void emit_inner0(TCGv_i32 tmp2, TCGv_i32 a) { +tcg_gen_add_i32(tmp2, a, tcg_constant_i32(5)); +} + +// i32 inner1 +void emit_inner1(TCGv_i32 tmp2, TCGv_i32 a) { +tcg_gen_add_i32(tmp2, a, tcg_constant_i32(5)); +} + +// i32 outer1 +void emit_outer1(TCGv_i32 tmp5, TCGv_i32 cond, TCGv_i32 b) { +TCGv_i32 tmp6 =3D tcg_temp_new_i32(); +tcg_gen_add_i32(tmp6, b, tcg_constant_i32(5)); +tcg_gen_movcond_i32(TCG_COND_EQ, tmp5, cond, tcg_constant_i32(0), tcg_cons= tant_i32(0), tmp6); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/cpustate.c b/subproject= s/helper-to-tcg/tests/ref/21/cpustate.c new file mode 100644 index 0000000000..e022a14d0c --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/cpustate.c @@ -0,0 +1,36 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "cpustate.h" + +extern TCGv_i32 tcg_regs[32]; +extern TCGv_i32 tcg_a[8]; +extern TCGv_i32 tcg_field; +// i32 helper_reg +void emit_reg(TCGv_i32 tmp5, TCGv_ptr env, uint32_t i) { +tcg_gen_mov_i32(tmp5, tcg_regs[((uint64_t) (uint32_t) i)]); +} + +// i32 helper_data_a +void emit_data_a(TCGv_i32 tmp6, TCGv_ptr env, uint32_t i) { +tcg_gen_mov_i32(tmp6, tcg_a[((uint64_t) (uint32_t) i)]); +} + +// i32 helper_single_mapped +void emit_single_mapped(TCGv_i32 tmp4, TCGv_ptr env) { +tcg_gen_mov_i32(tmp4, tcg_field); +} + +// i32 helper_unmapped +void emit_unmapped(TCGv_i32 tmp2, TCGv_ptr env) { +TCGv_ptr ptr3 =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(ptr3, env, 128ull); +tcg_gen_ld_i32(tmp2, ptr3, 0); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/forward-context.c b/sub= projects/helper-to-tcg/tests/ref/21/forward-context.c new file mode 100644 index 0000000000..a1c0e5f37a --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/forward-context.c @@ -0,0 +1,30 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "translate.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "forward-context.h" + +#include "translate.h" +// i32 f0 +void emit_f0(DisasContext *ctx, TCGv_i32 tmp2, TCGv_i32 a, TCGv_i32 off) { +TCGv_i32 tmp3 =3D tcg_temp_new_i32(); +tmp3 =3D fdecl0(ctx, off); +tcg_gen_add_i32(tmp2, tmp3, a); +} + +// i32 f1 +void emit_f1(DisasContext *ctx, TCGv_i32 tmp2, TCGv_i32 a) { +TCGv_i32 tmp4 =3D tcg_temp_new_i32(); +tmp4 =3D fdecl0(ctx, a); +tcg_gen_sub_i32(tmp2, tcg_constant_i32(0), a); +TCGv_i32 tmp3 =3D tcg_temp_new_i32(); +tmp3 =3D fdecl0(ctx, tmp2); +tcg_gen_add_i32(tmp2, tmp3, tmp4); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/ldst.c b/subprojects/he= lper-to-tcg/tests/ref/21/ldst.c new file mode 100644 index 0000000000..5710b0b285 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/ldst.c @@ -0,0 +1,21 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "ldst.h" + +// i32 helper_ld8 +void emit_ld8(TCGv_i32 tmp4, TCGv_ptr env, TCGv_i32 addr) { +tcg_gen_qemu_ld_i32(tmp4, addr, tb_mmu_index(tcg_ctx->gen_tb->flags), MO_8= ); +} + +// void helper_st8 +void emit_st8(TCGv_ptr env, TCGv_i32 addr, TCGv_i32 data) { +tcg_gen_qemu_st_i32(data, addr, tb_mmu_index(tcg_ctx->gen_tb->flags), MO_8= ); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/scalar.c b/subprojects/= helper-to-tcg/tests/ref/21/scalar.c new file mode 100644 index 0000000000..50fe4307c0 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/scalar.c @@ -0,0 +1,21 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "scalar.h" + +// i32 helper_add +void emit_add(TCGv_i32 tmp2, TCGv_i32 a, TCGv_i32 b) { +tcg_gen_add_i32(tmp2, b, a); +} + +// i32 helper_cmov +void emit_cmov(TCGv_i32 tmp5, TCGv_i32 c0, TCGv_i32 c1, TCGv_i32 a, TCGv_i= 32 b) { +tcg_gen_movcond_i32(TCG_COND_LTU, tmp5, c0, c1, a, b); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/user-pcrel-jump.c b/sub= projects/helper-to-tcg/tests/ref/21/user-pcrel-jump.c new file mode 100644 index 0000000000..68e6c5d441 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/user-pcrel-jump.c @@ -0,0 +1,33 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "user-pcrel-jump.h" + +// void prcel_jump +void emit_prcel_jump(TCGv_i32 off) { +TCGv_i32 ea =3D tcg_temp_new_i32(); +tcg_gen_shl_i32(ea, off, tcg_constant_i32(2)); +tcg_gen_or_i32(ea, ea, tcg_constant_i32(3)); +target_pcrel_jump(ea); +} + +// void prcel_condjump +void emit_prcel_condjump(TCGv_i32 cond, TCGv_i32 off) { +TCGLabel * label8 =3D gen_new_label(); +TCGLabel * label9 =3D gen_new_label(); +tcg_gen_brcondi_i32(TCG_COND_EQ, cond, 0, label8); +gen_set_label(label9); +TCGv_i32 ea =3D tcg_temp_new_i32(); +tcg_gen_shl_i32(ea, off, tcg_constant_i32(2)); +tcg_gen_or_i32(ea, ea, tcg_constant_i32(3)); +target_pcrel_jump(ea); +tcg_gen_br(label8); +gen_set_label(label8); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f16L.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-f16L.c new file mode 100644 index 0000000000..146c940bd4 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f16L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f16L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 2; +const size_t ci =3D i % 8; +const size_t bc =3D c % 2; +return 16 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 2; +const size_t ci =3D i % 4; +const size_t bc =3D c % 2; +return 8 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 2; +const size_t ci =3D i % 2; +const size_t bc =3D c % 2; +return 4 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 2; +const size_t ci =3D i % 1; +const size_t bc =3D c % 2; +return 2 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x807060504030201, 0x100F0E0D0C0B0A= 09, 0x1817161514131211, 0x201F1E1D1C1B1A19}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f16M.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-f16M.c new file mode 100644 index 0000000000..76cff20bee --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f16M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f16M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 2; +const size_t ci =3D i % 8; +const size_t bc =3D c % 2; +return 16 * b + 8 * (1 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 2; +const size_t ci =3D i % 4; +const size_t bc =3D c % 2; +return 8 * b + 4 * (1 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 2; +const size_t ci =3D i % 2; +const size_t bc =3D c % 2; +return 4 * b + 2 * (1 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 2; +const size_t ci =3D i % 1; +const size_t bc =3D c % 2; +return 2 * b + 1 * (1 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x90A0B0C0D0E0F10, 0x10203040506070= 8, 0x191A1B1C1D1E1F20, 0x1112131415161718}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f32L.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-f32L.c new file mode 100644 index 0000000000..8515b3488e --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f32L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f32L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 4; +const size_t ci =3D i % 8; +const size_t bc =3D c % 4; +return 32 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 4; +const size_t ci =3D i % 4; +const size_t bc =3D c % 4; +return 16 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 4; +const size_t ci =3D i % 2; +const size_t bc =3D c % 4; +return 8 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 4; +const size_t ci =3D i % 1; +const size_t bc =3D c % 4; +return 4 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x807060504030201, 0x100F0E0D0C0B0A= 09, 0x1817161514131211, 0x201F1E1D1C1B1A19}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f32M.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-f32M.c new file mode 100644 index 0000000000..41067c4c62 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f32M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f32M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 4; +const size_t ci =3D i % 8; +const size_t bc =3D c % 4; +return 32 * b + 8 * (3 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 4; +const size_t ci =3D i % 4; +const size_t bc =3D c % 4; +return 16 * b + 4 * (3 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 4; +const size_t ci =3D i % 2; +const size_t bc =3D c % 4; +return 8 * b + 2 * (3 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 4; +const size_t ci =3D i % 1; +const size_t bc =3D c % 4; +return 4 * b + 1 * (3 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x191A1B1C1D1E1F20, 0x1112131415161= 718, 0x90A0B0C0D0E0F10, 0x102030405060708}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f64L.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-f64L.c new file mode 100644 index 0000000000..d8e660be8b --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f64L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f64L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 8; +const size_t ci =3D i % 8; +const size_t bc =3D c % 8; +return 64 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 8; +const size_t ci =3D i % 4; +const size_t bc =3D c % 8; +return 32 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 8; +const size_t ci =3D i % 2; +const size_t bc =3D c % 8; +return 16 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 8; +const size_t ci =3D i % 1; +const size_t bc =3D c % 8; +return 8 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x807060504030201, 0x100F0E0D0C0B0A= 09, 0x1817161514131211, 0x201F1E1D1C1B1A19}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f64M.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-f64M.c new file mode 100644 index 0000000000..facfe730c1 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f64M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f64M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 8; +const size_t ci =3D i % 8; +const size_t bc =3D c % 8; +return 64 * b + 8 * (7 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 8; +const size_t ci =3D i % 4; +const size_t bc =3D c % 8; +return 32 * b + 4 * (7 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 8; +const size_t ci =3D i % 2; +const size_t bc =3D c % 8; +return 16 * b + 2 * (7 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 8; +const size_t ci =3D i % 1; +const size_t bc =3D c % 8; +return 8 * b + 1 * (7 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x191A1B1C1D1E1F20, 0x1112131415161= 718, 0x90A0B0C0D0E0F10, 0x102030405060708}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f8L.c b/s= ubprojects/helper-to-tcg/tests/ref/21/vector-layout-f8L.c new file mode 100644 index 0000000000..98f4d0a584 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f8L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f8L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 1; +const size_t ci =3D i % 8; +const size_t bc =3D c % 1; +return 8 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 1; +const size_t ci =3D i % 4; +const size_t bc =3D c % 1; +return 4 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 1; +const size_t ci =3D i % 2; +const size_t bc =3D c % 1; +return 2 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 1; +const size_t ci =3D i % 1; +const size_t bc =3D c % 1; +return 1 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x807060504030201, 0x100F0E0D0C0B0A= 09, 0x1817161514131211, 0x201F1E1D1C1B1A19}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f8M.c b/s= ubprojects/helper-to-tcg/tests/ref/21/vector-layout-f8M.c new file mode 100644 index 0000000000..a768efc628 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-f8M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-f8M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 1; +const size_t ci =3D i % 8; +const size_t bc =3D c % 1; +return 8 * b + 8 * (0 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 1; +const size_t ci =3D i % 4; +const size_t bc =3D c % 1; +return 4 * b + 4 * (0 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 1; +const size_t ci =3D i % 2; +const size_t bc =3D c % 1; +return 2 * b + 2 * (0 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 1; +const size_t ci =3D i % 1; +const size_t bc =3D c % 1; +return 1 * b + 1 * (0 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x102030405060708, 0x90A0B0C0D0E0F1= 0, 0x1112131415161718, 0x191A1B1C1D1E1F20}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t16L.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-t16L.c new file mode 100644 index 0000000000..ca6944fa92 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t16L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t16L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 2; +const size_t ci =3D i % 8; +const size_t bc =3D c % 2; +return 16 * b + 8 * (1 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 2; +const size_t ci =3D i % 4; +const size_t bc =3D c % 2; +return 8 * b + 4 * (1 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 2; +const size_t ci =3D i % 2; +const size_t bc =3D c % 2; +return 4 * b + 2 * (1 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 2; +const size_t ci =3D i % 1; +const size_t bc =3D c % 2; +return 2 * b + 1 * (1 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x100F0E0D0C0B0A09, 0x8070605040302= 01, 0x201F1E1D1C1B1A19, 0x1817161514131211}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t16M.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-t16M.c new file mode 100644 index 0000000000..a4e0ca054f --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t16M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t16M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 2; +const size_t ci =3D i % 8; +const size_t bc =3D c % 2; +return 16 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 2; +const size_t ci =3D i % 4; +const size_t bc =3D c % 2; +return 8 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 2; +const size_t ci =3D i % 2; +const size_t bc =3D c % 2; +return 4 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 2; +const size_t ci =3D i % 1; +const size_t bc =3D c % 2; +return 2 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x102030405060708, 0x90A0B0C0D0E0F1= 0, 0x1112131415161718, 0x191A1B1C1D1E1F20}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t32L.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-t32L.c new file mode 100644 index 0000000000..b142d9b8ce --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t32L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t32L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 4; +const size_t ci =3D i % 8; +const size_t bc =3D c % 4; +return 32 * b + 8 * (3 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 4; +const size_t ci =3D i % 4; +const size_t bc =3D c % 4; +return 16 * b + 4 * (3 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 4; +const size_t ci =3D i % 2; +const size_t bc =3D c % 4; +return 8 * b + 2 * (3 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 4; +const size_t ci =3D i % 1; +const size_t bc =3D c % 4; +return 4 * b + 1 * (3 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x201F1E1D1C1B1A19, 0x1817161514131= 211, 0x100F0E0D0C0B0A09, 0x807060504030201}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t32M.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-t32M.c new file mode 100644 index 0000000000..109ab19c39 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t32M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t32M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 4; +const size_t ci =3D i % 8; +const size_t bc =3D c % 4; +return 32 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 4; +const size_t ci =3D i % 4; +const size_t bc =3D c % 4; +return 16 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 4; +const size_t ci =3D i % 2; +const size_t bc =3D c % 4; +return 8 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 4; +const size_t ci =3D i % 1; +const size_t bc =3D c % 4; +return 4 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x102030405060708, 0x90A0B0C0D0E0F1= 0, 0x1112131415161718, 0x191A1B1C1D1E1F20}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t64L.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-t64L.c new file mode 100644 index 0000000000..4f325caa75 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t64L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t64L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 8; +const size_t ci =3D i % 8; +const size_t bc =3D c % 8; +return 64 * b + 8 * (7 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 8; +const size_t ci =3D i % 4; +const size_t bc =3D c % 8; +return 32 * b + 4 * (7 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 8; +const size_t ci =3D i % 2; +const size_t bc =3D c % 8; +return 16 * b + 2 * (7 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 8; +const size_t ci =3D i % 1; +const size_t bc =3D c % 8; +return 8 * b + 1 * (7 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x201F1E1D1C1B1A19, 0x1817161514131= 211, 0x100F0E0D0C0B0A09, 0x807060504030201}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t64M.c b/= subprojects/helper-to-tcg/tests/ref/21/vector-layout-t64M.c new file mode 100644 index 0000000000..766a827128 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t64M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t64M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 8; +const size_t ci =3D i % 8; +const size_t bc =3D c % 8; +return 64 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 8; +const size_t ci =3D i % 4; +const size_t bc =3D c % 8; +return 32 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 8; +const size_t ci =3D i % 2; +const size_t bc =3D c % 8; +return 16 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 8; +const size_t ci =3D i % 1; +const size_t bc =3D c % 8; +return 8 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x102030405060708, 0x90A0B0C0D0E0F1= 0, 0x1112131415161718, 0x191A1B1C1D1E1F20}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t8L.c b/s= ubprojects/helper-to-tcg/tests/ref/21/vector-layout-t8L.c new file mode 100644 index 0000000000..18feb85fad --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t8L.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t8L.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 1; +const size_t ci =3D i % 8; +const size_t bc =3D c % 1; +return 8 * b + 8 * (0 - bc) + (7 - ci); +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 1; +const size_t ci =3D i % 4; +const size_t bc =3D c % 1; +return 4 * b + 4 * (0 - bc) + (3 - ci); +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 1; +const size_t ci =3D i % 2; +const size_t bc =3D c % 1; +return 2 * b + 2 * (0 - bc) + (1 - ci); +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 1; +const size_t ci =3D i % 1; +const size_t bc =3D c % 1; +return 1 * b + 1 * (0 - bc) + (0 - ci); +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x807060504030201, 0x100F0E0D0C0B0A= 09, 0x1817161514131211, 0x201F1E1D1C1B1A19}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x807060504030201); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t8M.c b/s= ubprojects/helper-to-tcg/tests/ref/21/vector-layout-t8M.c new file mode 100644 index 0000000000..97ebe17e91 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector-layout-t8M.c @@ -0,0 +1,527 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector-layout-t8M.h" + +#define HELPER_H "helper-to-tcg-support-helpers.h" +#include "exec/helper-proto-common.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen-common.h" +#include "exec/helper-gen.h.inc" + +inline size_t ind_8(size_t i) { +const size_t c =3D i / 8; +const size_t b =3D c / 1; +const size_t ci =3D i % 8; +const size_t bc =3D c % 1; +return 8 * b + 8 * bc + ci; +} + +inline size_t ind_16(size_t i) { +const size_t c =3D i / 4; +const size_t b =3D c / 1; +const size_t ci =3D i % 4; +const size_t bc =3D c % 1; +return 4 * b + 4 * bc + ci; +} + +inline size_t ind_32(size_t i) { +const size_t c =3D i / 2; +const size_t b =3D c / 1; +const size_t ci =3D i % 2; +const size_t bc =3D c % 1; +return 2 * b + 2 * bc + ci; +} + +inline size_t ind_64(size_t i) { +const size_t c =3D i / 1; +const size_t b =3D c / 1; +const size_t ci =3D i % 1; +const size_t bc =3D c % 1; +return 1 * b + 1 * bc + ci; +} + +void HELPER(vec_trunc_16_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_16_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_16_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_16(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_32(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_8)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint8_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_8(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_8(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint8_t)); ++i) { +uint8_t aa =3D *((uint8_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_8_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int8_t)); ++i) { +int8_t aa =3D *((int8_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_8_64(intptr_t dofs, intptr_t= aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_8_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_32_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_32_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_32_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_32(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_16)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint16_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_16(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_16(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint16_t)); ++i) { +uint16_t aa =3D *((uint16_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_16_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int16_t)); ++i) { +int16_t aa =3D *((int16_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_16_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_16_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_trunc_64_32)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint64_t)); ++i) { +uint64_t aa =3D *((uint64_t *) a + i); +*((uint32_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_trunc_64_32(intptr_t dofs, intptr= _t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_trunc_64_32(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_zext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(uint32_t)); ++i) { +uint32_t aa =3D *((uint32_t *) a + i); +*((uint64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_zext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_zext_32_64(d, a, tcg_constant_i32(size)); +} + +void HELPER(vec_sext_32_64)(void *d, void *a, uint32_t size) +{ +for (intptr_t i =3D 0; i < (size / sizeof(int32_t)); ++i) { +int32_t aa =3D *((int32_t *) a + i); +*((int64_t *) d + i) =3D aa; +} +} + +static inline void G_GNUC_UNUSED gen_vec_sext_32_64(intptr_t dofs, intptr_= t aofs, uint32_t size) +{ +TCGv_ptr d =3D tcg_temp_new_ptr(); +TCGv_ptr a =3D tcg_temp_new_ptr(); +tcg_gen_addi_ptr(d, tcg_env, dofs); +tcg_gen_addi_ptr(a, tcg_env, aofs); +gen_helper_vec_sext_32_64(d, a, tcg_constant_i32(size)); +} + +typedef struct VectorMem { + uint32_t allocated; +} VectorMem; + +static intptr_t temp_new_gvec(VectorMem *mem, uint32_t size) +{ + uint32_t off =3D ROUND_UP(mem->allocated, size); + g_assert(off + size <=3D STRUCT_SIZEOF_FIELD(CPUArchState, tmp_vmem)); + mem->allocated =3D off + size; + return offsetof(CPUArchState, tmp_vmem) + off; +} +// void helper_vec_constant +void emit_vec_constant(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +static const uint64_t vec4_data[] =3D {0x102030405060708, 0x90A0B0C0D0E0F1= 0, 0x1112131415161718, 0x191A1B1C1D1E1F20}; +tcg_gen_gvec_mov_var(MO_64, tcg_env, vec4, tcg_constant_ptr(vec4_data), 0,= 32, 32); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_splat +void emit_vec_splat(intptr_t d, intptr_t a) { +VectorMem mem =3D {0}; +intptr_t vec4 =3D temp_new_gvec(&mem, 32); +tcg_gen_gvec_dup_imm(MO_64, vec4, 32, 32, 0x102030405060708); +tcg_gen_gvec_add(MO_8, d, a, vec4, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint8_t +void emit_vec_trunc_uint64_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 32); +gen_vec_trunc_64_8(vec5, b, 256); +tcg_gen_gvec_add(MO_8, d, vec5, vec6, 32, 32); +} + +// void helper_vec_trunc_uint64_t_uint16_t +void emit_vec_trunc_uint64_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec6, a, 256); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_trunc_64_16(vec5, b, 256); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_trunc_uint32_t_uint8_t +void emit_vec_trunc_uint32_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_8(d, vec6, 128); +} + +// void helper_vec_trunc_uint32_t_uint16_t +void emit_vec_trunc_uint32_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +tcg_gen_gvec_add(MO_32, vec6, b, a, 128, 128); +gen_vec_trunc_32_16(d, vec6, 128); +} + +// void helper_vec_trunc_uint16_t_uint8_t +void emit_vec_trunc_uint16_t_uint8_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +tcg_gen_gvec_add(MO_16, vec6, b, a, 64, 64); +gen_vec_trunc_16_8(d, vec6, 64); +} + +// void helper_vec_zext_uint8_t_uint64_t +void emit_vec_zext_uint8_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint16_t_uint64_t +void emit_vec_zext_uint16_t_uint64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_zext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_zext_uint8_t_uint32_t +void emit_vec_zext_uint8_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint16_t_uint32_t +void emit_vec_zext_uint16_t_uint32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_zext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_zext_uint8_t_uint16_t +void emit_vec_zext_uint8_t_uint16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_zext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + +// void helper_vec_sext_int8_t_int64_t +void emit_vec_sext_int8_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_8_64(vec5, b, 32); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int16_t_int64_t +void emit_vec_sext_int16_t_int64_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 256); +gen_vec_sext_16_64(vec5, b, 64); +tcg_gen_gvec_add(MO_64, d, vec5, vec6, 256, 256); +} + +// void helper_vec_sext_int8_t_int32_t +void emit_vec_sext_int8_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_8_32(vec5, b, 32); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int16_t_int32_t +void emit_vec_sext_int16_t_int32_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec6, a, 64); +intptr_t vec5 =3D temp_new_gvec(&mem, 128); +gen_vec_sext_16_32(vec5, b, 64); +tcg_gen_gvec_add(MO_32, d, vec5, vec6, 128, 128); +} + +// void helper_vec_sext_int8_t_int16_t +void emit_vec_sext_int8_t_int16_t(intptr_t d, intptr_t a, intptr_t b) { +VectorMem mem =3D {0}; +intptr_t vec6 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec6, a, 32); +intptr_t vec5 =3D temp_new_gvec(&mem, 64); +gen_vec_sext_8_16(vec5, b, 32); +tcg_gen_gvec_add(MO_16, d, vec5, vec6, 64, 64); +} + diff --git a/subprojects/helper-to-tcg/tests/ref/21/vector.c b/subprojects/= helper-to-tcg/tests/ref/21/vector.c new file mode 100644 index 0000000000..deeec8e8ab --- /dev/null +++ b/subprojects/helper-to-tcg/tests/ref/21/vector.c @@ -0,0 +1,31 @@ +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "translate.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "tcg/tcg.h" +#include "tcg/tcg-global-mappings.h" +#include "exec/translation-block.h" +#include "vector.h" + +// void helper_vec_splat_reg +void emit_vec_splat_reg(intptr_t d, TCGv_i32 imm) { +tcg_gen_gvec_dup_i32(MO_8, d, 32ull, 32ull, imm); +} + +// void helper_vec_splat_imm +void emit_vec_splat_imm(intptr_t d, uint8_t imm) { +tcg_gen_gvec_dup_imm(MO_8, d, 32ull, 32ull, imm); +} + +// void helper_vec_add +void emit_vec_add(intptr_t d, intptr_t a, intptr_t b) { +tcg_gen_gvec_add(MO_8, d, b, a, 32, 32); +} + +// void helper_vec_add32 +void emit_vec_add32(intptr_t d, intptr_t a, intptr_t b) { +tcg_gen_gvec_add(MO_32, d, b, a, 128, 128); +} + diff --git a/subprojects/helper-to-tcg/tests/scalar.c b/subprojects/helper-= to-tcg/tests/scalar.c new file mode 100644 index 0000000000..09af72371d --- /dev/null +++ b/subprojects/helper-to-tcg/tests/scalar.c @@ -0,0 +1,15 @@ +#include + +/* Simple arithmetic */ +uint32_t helper_add(uint32_t a, uint32_t b) { + return a + b; +} + +/* Control flow reducable to conditinal move */ +uint32_t helper_cmov(uint32_t c0, uint32_t c1, uint32_t a, uint32_t b) { + if (c0 < c1) { + return a; + } else { + return b; + } +} diff --git a/subprojects/helper-to-tcg/tests/tcg-global-mappings.h b/subpro= jects/helper-to-tcg/tests/tcg-global-mappings.h new file mode 100644 index 0000000000..341dcd20b3 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/tcg-global-mappings.h @@ -0,0 +1,118 @@ +/* + * Copyright(c) 2026 rev.ng Labs Srl. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef TCG_GLOBAL_MAP_H +#define TCG_GLOBAL_MAP_H + +/** + * cpu_tcg_mapping: Declarative mapping of offsets into a struct to global + * TCGvs. Parseable by LLVM-based tools. + * @tcg_var_name: String name of the TCGv to use as destination of the map= ping. + * @tcg_var_base_address: Address of the above TCGv. + * @cpu_type_name: String name of the base type being mapped, e.g. "CPUArc= hState". + * @cpu_var_names: Array of printable names of TCGvs, used when calling + * tcg_global_mem_new from init_cpu_tcg_mappings. Contains + * @number_of_elements strings. + * @cpu_var_base_offset: Base offset of field in the source struct. + * @cpu_var_size: Size of field in the source struct, if the field is an a= rray, + * this holds the size of the element type. + * @cpu_var_stride: Stride between array elements in the source struct. T= his + * can be greater than the element size when mapping a fi= eld + * in an array of structs. + * @number_of_elements: Number of elements of array in the source struct. + */ +typedef struct cpu_tcg_mapping { + const char *tcg_var_name; + void *tcg_var_base_address; + + const char *cpu_type_name; + const char *const *cpu_var_names; + size_t cpu_var_base_offset; + size_t cpu_var_size; + size_t cpu_var_stride; + + size_t number_of_elements; +} cpu_tcg_mapping; + +#define STRUCT_SIZEOF_FIELD(S, member) sizeof(((S *)0)->member) + +#define STRUCT_ARRAY_SIZE(S, array) = \ + (STRUCT_SIZEOF_FIELD(S, array) / STRUCT_SIZEOF_FIELD(S, array[0])) + +/* + * Following are a few macros that aid in constructing + * `cpu_tcg_mapping`s for a few common cases. + */ + +/* Map between single CPU register and to TCG global */ +#define CPU_TCG_MAP(struct_type, tcg_var, cpu_var) = \ + (cpu_tcg_mapping) = \ + { = \ + .tcg_var_name =3D stringify(tcg_var), = \ + .tcg_var_base_address =3D &tcg_var, = \ + .cpu_type_name =3D stringify(struct_type), = \ + .cpu_var_names =3D (const char *[]){stringify(cpu_var)}, = \ + .cpu_var_base_offset =3D offsetof(struct_type, cpu_var), = \ + .cpu_var_size =3D STRUCT_SIZEOF_FIELD(struct_type, cpu_var), = \ + .cpu_var_stride =3D 0, .number_of_elements =3D 1, = \ + } + +/* Map between array of CPU registers and array of TCG globals. */ +#define CPU_TCG_MAP_ARRAY(struct_type, tcg_var, cpu_var, names) = \ + (cpu_tcg_mapping) = \ + { = \ + .tcg_var_name =3D stringify(tcg_var), = \ + .tcg_var_base_address =3D tcg_var, = \ + .cpu_type_name =3D stringify(struct_type), = \ + .cpu_var_names =3D names, = \ + .cpu_var_base_offset =3D offsetof(struct_type, cpu_var), = \ + .cpu_var_size =3D STRUCT_SIZEOF_FIELD(struct_type, cpu_var[0]), = \ + .cpu_var_stride =3D STRUCT_SIZEOF_FIELD(struct_type, cpu_var[0]), = \ + .number_of_elements =3D STRUCT_ARRAY_SIZE(struct_type, cpu_var), = \ + } + +/* + * Map between single member in an array of structs to an array + * of TCG globals, e.g. maps + * + * cpu_state.array_of_structs[i].member + * + * to + * + * tcg_global_member[i] + */ +#define CPU_TCG_MAP_ARRAY_OF_STRUCTS(struct_type, tcg_var, cpu_struct, = \ + cpu_var, names) = \ + (cpu_tcg_mapping) = \ + { = \ + .tcg_var_name =3D stringify(tcg_var), = \ + .tcg_var_base_address =3D tcg_var, = \ + .cpu_type_name =3D stringify(struct_type), = \ + .cpu_var_names =3D names, = \ + .cpu_var_base_offset =3D offsetof(struct_type, cpu_struct[0].cpu_v= ar), \ + .cpu_var_size =3D = \ + STRUCT_SIZEOF_FIELD(struct_type, cpu_struct[0].cpu_var), = \ + .cpu_var_stride =3D STRUCT_SIZEOF_FIELD(struct_type, cpu_struct[0]= ), \ + .number_of_elements =3D STRUCT_ARRAY_SIZE(struct_type, cpu_struct)= , \ + } + +extern cpu_tcg_mapping tcg_global_mappings[]; +extern size_t tcg_global_mapping_count; + +void init_cpu_tcg_mappings(cpu_tcg_mapping *mappings, size_t size); + +#endif /* TCG_GLOBAL_MAP_H */ diff --git a/subprojects/helper-to-tcg/tests/user-pcrel-jump.c b/subproject= s/helper-to-tcg/tests/user-pcrel-jump.c new file mode 100644 index 0000000000..7c0f89c374 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/user-pcrel-jump.c @@ -0,0 +1,28 @@ +/* + * Test translation custom jump instructions + * + * (experimental) + */ + +#define ANNOTATE(str) __attribute__((annotate("helper-to-tcg"))) + +ANNOTATE("immediate: 0") +void target_pcrel_jump(int pc); +ANNOTATE("immediate: 0") +void target_pcrel_jump_cond(int pc); +ANNOTATE("immediate: 0") +void target_pcrel_jump_fall(int pc); + +ANNOTATE("helper-to-tcg") +void prcel_jump(int off) { + int ea =3D 4*off + 3; + target_pcrel_jump(ea); +} + +ANNOTATE("helper-to-tcg") +void prcel_condjump(int cond, int off) { + if (cond) { + int ea =3D 4*off + 3; + target_pcrel_jump(ea); + } +} diff --git a/subprojects/helper-to-tcg/tests/vector-layout.c b/subprojects/= helper-to-tcg/tests/vector-layout.c new file mode 100644 index 0000000000..fa7d1857c7 --- /dev/null +++ b/subprojects/helper-to-tcg/tests/vector-layout.c @@ -0,0 +1,51 @@ +#include +#include + +__attribute__((annotate("ptr-to-offset: 0, 1"))) void +helper_vec_constant(void *restrict d, void *restrict a) { + const uint8_t arr[] =3D { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + }; + for (int i =3D 0; i < 32; ++i) { + ((uint8_t *)d)[i] =3D ((uint8_t *)a)[i] + arr[i]; + } +} + +__attribute__((annotate("ptr-to-offset: 0, 1"))) void +helper_vec_splat(void *restrict d, void *restrict a) { + const uint8_t arr[] =3D { + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, + }; + for (int i =3D 0; i < 32; ++i) { + ((uint8_t *)d)[i] =3D ((uint8_t *)a)[i] + arr[i]; + } +} + +#define GENSZ(NAME, SRC, DST) = \ + __attribute__((annotate("ptr-to-offset: 0, 1, 2"))) void = \ + helper_vec_##NAME##_##SRC##_##DST(void *restrict d, void *restrict a, = \ + void *restrict b) { = \ + for (int i =3D 0; i < 32; ++i) { = \ + ((DST *)d)[i] =3D (DST)((SRC *)a)[i] + (DST)((SRC *)b)[i]; = \ + } = \ + } + +GENSZ(trunc, uint64_t, uint8_t) +GENSZ(trunc, uint64_t, uint16_t) +GENSZ(trunc, uint32_t, uint8_t) +GENSZ(trunc, uint32_t, uint16_t) +GENSZ(trunc, uint16_t, uint8_t) + +GENSZ(zext, uint8_t, uint64_t) +GENSZ(zext, uint16_t, uint64_t) +GENSZ(zext, uint8_t, uint32_t) +GENSZ(zext, uint16_t, uint32_t) +GENSZ(zext, uint8_t, uint16_t) + +GENSZ(sext, int8_t, int64_t) +GENSZ(sext, int16_t, int64_t) +GENSZ(sext, int8_t, int32_t) +GENSZ(sext, int16_t, int32_t) +GENSZ(sext, int8_t, int16_t) diff --git a/subprojects/helper-to-tcg/tests/vector.c b/subprojects/helper-= to-tcg/tests/vector.c new file mode 100644 index 0000000000..b823976dca --- /dev/null +++ b/subprojects/helper-to-tcg/tests/vector.c @@ -0,0 +1,34 @@ +#include + +__attribute__((annotate("ptr-to-offset: 0"))) void +helper_vec_splat_reg(void *restrict d, uint8_t imm) +{ + for (int i =3D 0; i < 32; ++i) { + ((uint8_t *)d)[i] =3D imm; + } +} + +__attribute__((annotate("immediate: 1"))) +__attribute__((annotate("ptr-to-offset: 0"))) void +helper_vec_splat_imm(void *restrict d, uint8_t imm) +{ + for (int i =3D 0; i < 32; ++i) { + ((uint8_t *)d)[i] =3D imm; + } +} + +__attribute__((annotate("ptr-to-offset: 0, 1, 2"))) void +helper_vec_add(void *restrict d, void *restrict a, void *restrict b) +{ + for (int i =3D 0; i < 32; ++i) { + ((uint8_t *)d)[i] =3D ((uint8_t *)a)[i] + ((uint8_t *)b)[i]; + } +} + +__attribute__((annotate("ptr-to-offset: 0, 1, 2"))) void +helper_vec_add32(void *restrict d, void *restrict a, void *restrict b) +{ + for (int i =3D 0; i < 32; ++i) { + ((uint32_t *)d)[i] =3D ((uint32_t *)a)[i] + ((uint32_t *)b)[i]; + } +} --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381147; cv=none; d=zohomail.com; s=zohoarc; b=PQyGkjMvndR5ZayHtai6W2YBkW/HSUsBW4ha/Kt29PXqirMJJ81EUFUZSjVteBY5rsIbp2ESFaalPS6zCUoTmpGj1eGcHz4A6CKOu5Law5vKJ79PeS3+NDIwu6PSva9XijTlAif9agsJa4V+bZeXXLAepw/MFWE1eNk4J2Ww+cc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381147; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=/gX7vydUrF0eZ3CQcu0iax3KTvhaY4aX0Vs4FvDZaLo=; b=RL+IA0P6MFdwj7wg4ur8aeH95UKAQtn1jZ4TN095OF2c9qd+1xjQ7gixWPyLnk4wkztIWJJ3YJKrkhP8UkuKofzU0Bn7zWHNWB5mhs31ZFCYxxvwtBmafe2Se7eeJ5bqHSOAsRoDcUpZgGMRpRAiQNoYAYKKxMNcMcMyZEU8AEo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381147492479.52338012293285; Wed, 29 Jul 2026 20:12:27 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7a-0004w5-EF; Wed, 29 Jul 2026 23:07:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7H-0004hK-Uh for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:29 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7E-00030u-3h for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=/gX7vydUrF0eZ3CQcu0iax3KTvhaY4aX0Vs4FvDZaLo=; b=hiDBo0GUW2Vf9BD EsYmAF1ZqSBzEsQfK98tbpGqce5WYvGTW2OGWK2BHKja4MK5VcoHgB17TAeo+QImoiSUjgWYQIAtO XOlV6mlG30Ag16TFELwyJrFA6ahUSLNHDSn3bVjFFGxPxgJJM+IrXioq5kbX8nEcd7PQdFBaZv0Re TQ=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 40/50] test: helper-to-tcg docker tests Date: Thu, 30 Jul 2026 05:10:14 +0200 Message-ID: <20260730031025.12926-41-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381148143158500 Content-Type: text/plain; charset="utf-8" Adds a docker container with LLVM versions 15-21 and a docker test for building helper-to-tcg and running end-to-end tests along with running check-tcg, for testing targets such as Hexagon. Signed-off-by: Anton Johansson -- NOTE: Last I checked I had some troubles with C++17 support within the container, was a while ago though. Reviewed-by: Alessandro Di Federico --- tests/docker/dockerfiles/debian-llvm.docker | 38 +++++++++++++++++++ tests/docker/test-helper-to-tcg | 41 +++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 tests/docker/dockerfiles/debian-llvm.docker create mode 100755 tests/docker/test-helper-to-tcg diff --git a/tests/docker/dockerfiles/debian-llvm.docker b/tests/docker/doc= kerfiles/debian-llvm.docker new file mode 100644 index 0000000000..7bfc084a34 --- /dev/null +++ b/tests/docker/dockerfiles/debian-llvm.docker @@ -0,0 +1,38 @@ +FROM docker.io/library/debian:11-slim + +RUN apt update && \ + DEBIAN_FRONTEND=3Dnoninteractive apt install -yy eatmydata && \ + DEBIAN_FRONTEND=3Dnoninteractive eatmydata \ + apt install -y --no-install-recommends \ + bison \ + ca-certificates \ + flex \ + gawk \ + libmpc-dev \ + libmpfr-dev \ + libglib2.0-dev \ + libpixman-1-dev \ + make \ + ninja-build \ + rsync \ + pkgconf \ + wget \ + lsb-release \ + software-properties-common \ + gnupg \ + meson \ + python3-pip \ + python3-setuptools \ + python3-venv \ + python3-wheel + +RUN /usr/bin/pip3 install tomli + +RUN wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh +RUN ./llvm.sh 15 all +RUN ./llvm.sh 16 all +RUN ./llvm.sh 17 all +RUN ./llvm.sh 18 all +RUN ./llvm.sh 19 all +RUN ./llvm.sh 20 all +RUN ./llvm.sh 21 all diff --git a/tests/docker/test-helper-to-tcg b/tests/docker/test-helper-to-= tcg new file mode 100755 index 0000000000..0c27040d60 --- /dev/null +++ b/tests/docker/test-helper-to-tcg @@ -0,0 +1,41 @@ +#!/bin/bash -e + +TEST_COMMAND=3D"" +TARGET_LIST=3D"" + +cd "$BUILD_DIR" + +# Checks helper-to-tcg builds and passes unit tests +# for targetted LLVM versions. Run meson from QEMU source so helper-to-tc= g tests can find +# `tcg-global-mappings.h`. +for version in {15..21}; do + llvm_config=3Dllvm-config-${version} + build_dir=3D"${BUILD_DIR}/build-helper-to-tcg-${version}" + cxx=3D$(${llvm_config} --bindir)/clang++ + [ ! -d ${build_dir} ] && mkdir ${build_dir} + CXX=3D${cxx} meson setup ${build_dir} ${QEMU_SRC}/subprojects/helper-t= o-tcg -Dllvm_config_path=3D${llvm_config} + meson compile -C ${build_dir} + meson test -C ${build_dir} --suite 'helper-to-tcg:helper-to-tcg' +done + +# Runs check-tcg for all LLVM versions +llvm_config_main=3Dllvm-config-15 +bin_main=3D$(${llvm_config_main} --bindir) +cc_main=3D${bin_main}/clang +cxx_main=3D${bin_main}/clang++ +for version in {15..21}; do + llvm_config=3Dllvm-config-${version} + build_dir=3Dbuild-qemu-${version} + bin=3D$(${llvm_config} --bindir) + cxx=3D${bin}/clang++ + cc=3D${bin}/clang + [ ! -d ${build_dir} ] && mkdir ${build_dir} + + pushd ${build_dir} + + TARGET_LIST=3D${TARGET_LIST:-$DEF_TARGET_LIST} \ + build_qemu "--cc=3D${cc_main} --cxx=3D${cxx_main} -Dhelper-to-tcg:llvm= _config_path=3D${llvm_config} --enable-debug-tcg" + check_tcg + + popd +done --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381108; cv=none; d=zohomail.com; s=zohoarc; b=FZ1bqoAtBlZAkSJejUW5gNxP7Ym7KnZJ9dt42gArCEfz0SispEoPW+zCOJoBrfkszqI6qzsIcmv7oOroxqy7Du2uY/bjZ2ZNPWaJEityx5ORodATxkBBvFhnd3GrXVyMtFg3u/TYQv6DOrdpevZIniyBzWi/TTu7AZsL1ysBTA8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381108; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=2vGWytjTwZWET4H4FTbOQuyUsF34x6Z1y1ZwobIFReg=; b=hJBJthORFtlzwwrS8cLN2REiK9r6LAxwgqVlr8FRXQfYqQpFolRhz7sCtCd6aWKfgHmNlcwk5M/Dl5ZD107ENeH8kfcqmJd02AtLDSSkqNz5L+phUVt/7jnsVPB1IJbSsrOvFPrW6imp/eNIm20lzh/VKRZImdCXv/WPFJwYqqg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381107780538.4692723665659; Wed, 29 Jul 2026 20:11:47 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7h-0005UB-Gj; Wed, 29 Jul 2026 23:07:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7H-0004gW-KQ for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:27 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7F-000312-Vk for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=2vGWytjTwZWET4H4FTbOQuyUsF34x6Z1y1ZwobIFReg=; b=IHaKI+aKDHXx5Rv EQy2hJcQupVOTsm0N6kWmKquhEOmEsGsm2LS80b3NIuBddj8KOP6w0Lx0dE3mWU5nc/NsL853XeLP rqwt0nvstV/QKXH8tHp05qGAWuoL8Hl4EdjU2hrL2vPRZdrv/Ddo/bUPa90pAal1HgcgQTMGoQDtl IM=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 41/50] target/hexagon: Add get_tb_mmu_index() Date: Thu, 30 Jul 2026 05:10:15 +0200 Message-ID: <20260730031025.12926-42-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381109989158500 Content-Type: text/plain; charset="utf-8" Adds a functions to return the current mmu index given tb_flags of the current translation block. Required by helper-to-tcg in order to retrieve the mmu index for memory operations without changing the signature of helper functions. Signed-off-by: Anton Johansson Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- target/hexagon/translate.c | 12 ++++++++++++ target/hexagon/translate.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 199b4f8c2e..bfd84bba4e 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -128,6 +128,18 @@ intptr_t ctx_tmp_vreg_off(DisasContext *ctx, int regnu= m, return offset; } =20 +#if defined(TARGET_HELPER_TO_TCG) +/* + * Returns the current mmu index given tb_flags of the current translation + * block. Required by helper-to-tcg in order to retrieve the mmu index for + * memory operations without changing the signature of helper functions. + */ +int get_tb_mmu_index(uint32_t flags) +{ + return FIELD_EX32(flags, TB_FLAGS, MMU_INDEX); +} +#endif + static void gen_exception(int excp, uint32_t PC) { gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp), diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index 2fca157553..6cf3b2fe3b 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -345,4 +345,8 @@ FIELD(PROBE_PKT_SCALAR_HVX_STORES, MMU_IDX, 5, 2) =20 void gen_framecheck(DisasContext *ctx, TCGv_i32 addr, TCGv_i32 ea); =20 +#if defined(TARGET_HELPER_TO_TCG) +int get_tb_mmu_index(uint32_t flags); +#endif + #endif --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381052; cv=none; d=zohomail.com; s=zohoarc; b=ESVUkg4AQu6itwipByBTJyl6Mrc7DTP76Ij6U5eTdUrZgmwjXo0zpNLscPdSVNzD5i1leMGKTD1fwzOaLV7Xx0W14axFzG1Buihhq/FwmFhrGlyhit0JRYbuNRx8PDv/GMIFGT6dozXCahSr8qdkd8+AlpoApz6BXJ4sM+5kG3c= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381052; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=KrUA14IUsSbr9Wds92GLD313FBynG/oxdLVdhWG7UhE=; b=Vysq360EUY8YH/Mx2DaXqKDmxnkEEO8deYSLMkBeROFCp15/QZ5SoFZRkbxuGHcIpvg437bYT0KguPJ3q2IgbUggPkhSOi0sugb4HvRrvYiHmi2g6ZK6nGOIvCpdfSfzDxsy21DsWJ9Cy/nc1uUrYcisltUTPwSR8HdM6N/cMXI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381052654510.3732808900302; Wed, 29 Jul 2026 20:10:52 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7h-0005US-LA; Wed, 29 Jul 2026 23:07:53 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7J-0004hR-E0 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:31 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7I-00031M-1O for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=KrUA14IUsSbr9Wds92GLD313FBynG/oxdLVdhWG7UhE=; b=XekgEHj6ybrt2rk FRLDRJKohelF5ibk5bfUpdfffWuHM5k/EFIOZDIYyxe0l87mBW53GRlHZyLID2O3vHRn26c0MP8J7 qAlEtXh71z6JL+ybLFxykEZ0aL9hTo1PSVxgiO/SElYUadlAp5keIZYrj9z3mW8COsupHpp7EaIDr Xs=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 42/50] target/hexagon: Increase VECTOR_TEMPS_MAX Date: Thu, 30 Jul 2026 05:10:16 +0200 Message-ID: <20260730031025.12926-43-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381053739158500 Content-Type: text/plain; charset="utf-8" Doubles the number of vector temporaries from 4 to 8, useful when emitting vector instructions with helper-to-tcg to handle more complicated helpers. `tmp_VRegs` must be later specified later to `helper-to-tcg` through `--temp-vector-block=3Dtmp_VRegs`. Signed-off-by: Anton Johansson --- target/hexagon/cpu.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 7694fd91fa..02ac011632 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -117,7 +117,7 @@ typedef struct { #define SET_EXCEPTION (env->status |=3D EXEC_STATUS_EXCEPTION) =20 /* Maximum number of vector temps in a packet */ -#define VECTOR_TEMPS_MAX 4 +#define VECTOR_TEMPS_MAX 8 =20 typedef struct CPUArchState { target_ulong gpr[TOTAL_PER_THREAD_REGS]; @@ -160,6 +160,10 @@ typedef struct CPUArchState { MMVector future_VRegs[VECTOR_TEMPS_MAX] QEMU_ALIGNED(16); MMVector tmp_VRegs[VECTOR_TEMPS_MAX] QEMU_ALIGNED(16); =20 +#ifdef TARGET_HELPER_TO_TCG + uint8_t tmp_vmem[4096] QEMU_ALIGNED(16); +#endif + MMQReg QRegs[NUM_QREGS] QEMU_ALIGNED(16); MMQReg future_QRegs[NUM_QREGS] QEMU_ALIGNED(16); =20 --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381042; cv=none; d=zohomail.com; s=zohoarc; b=Ya4QoM3JwhRfHGL8jEjc7zlZXpCSNJc6JhrqoFw1F3ajs/TEdBU3i6eB+05zkQ/DftdxcywU/pcU1ACryUNo7DE8zGqgiXYws4dsLTP0pMf+Arp6LUge1pI83a7H3CTk3KGiYmBktAy6KLhtu0mgzyDE93uIQOQRfbfJfs+EmNs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381042; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=e8S9uzCAuoCBY6pZkq2YHmBcWy9lWVl15Vgdc8Hi8NE=; b=Mm/1+5tBoyH+wLD+64DMmDKWQgZDpmR0hCRs4b+VNyTEvFM4UoKSbPcS4ZRYSwezrXUHehGItprnBlQUzFAMkQc1uSjg1LuUOzPdgKig0IwNYTBYihoP4zUMapopXFxTaQchb3OKZqMkXtMOwRrk/zw6Gm04VmVK43gRgL3JMzk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381042563109.21360617574669; Wed, 29 Jul 2026 20:10:42 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7Y-0004s0-Sl; Wed, 29 Jul 2026 23:07:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7J-0004hj-UR for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:33 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7I-00031S-27 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=e8S9uzCAuoCBY6pZkq2YHmBcWy9lWVl15Vgdc8Hi8NE=; b=a5+N7Iz2fTim1G3 X4kI48tN1CAF/qcd367wSQPI8cc9oMNTFtx2Iju/jmeISgB9Z9oBcfvd8snNymqFYEiUmat+UNcDd exenVIGZp85plwjn9oelnVV57ceIfKhYOULEEZPM2036dZb6me16bHv2ETJc8Q7JCgq6qZurCxsPv sk=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 43/50] target/hexagon: Provide env to tcg global mapping Date: Thu, 30 Jul 2026 05:10:17 +0200 Message-ID: <20260730031025.12926-44-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381043957158500 Content-Type: text/plain; charset="utf-8" Replaces previous calls to tcg_global_mem_new*() with a declarative global array of cpu_mapping structs. This array can be used to initialize all TCG globals with one function call from the target, and may additionally be used from LLVM based tools to map between offsets into a struct and a mapped TCGv global. Signed-off-by: Anton Johansson --- target/hexagon/translate.c | 119 ++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 62 deletions(-) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index bfd84bba4e..870475010b 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -33,6 +33,7 @@ #include "genptr.h" #include "printinsn.h" #include "exec/target_page.h" +#include "tcg/tcg-global-mappings.h" =20 #define HELPER_H "helper.h" #include "exec/helper-info.c.inc" @@ -1328,77 +1329,68 @@ static char store_val64_names[STORES_MAX][NAME_LEN]; static char vstore_addr_names[VSTORES_MAX][NAME_LEN]; static char vstore_size_names[VSTORES_MAX][NAME_LEN]; static char vstore_pending_names[VSTORES_MAX][NAME_LEN]; - -void hexagon_translate_init(void) -{ - int i; - - opcode_init(); +static const char *store_addr_names_ptr[STORES_MAX]; +static const char *store_width_names_ptr[STORES_MAX]; +static const char *store_val32_names_ptr[STORES_MAX]; +static const char *store_val64_names_ptr[STORES_MAX]; + +cpu_tcg_mapping tcg_global_mappings[] =3D { + /* General purpose and predicate registers */ + CPU_TCG_MAP_ARRAY(CPUHexagonState, hex_gpr, gpr, hexagon_regnames), + CPU_TCG_MAP_ARRAY(CPUHexagonState, hex_pred, pred, hexagon_prednames), + + /* Misc */ + CPU_TCG_MAP(CPUHexagonState, hex_new_value_usr, new_value_usr), + CPU_TCG_MAP(CPUHexagonState, hex_next_PC, next_PC), + CPU_TCG_MAP(CPUHexagonState, hex_slot_cancelled, slot_cancelled), + CPU_TCG_MAP(CPUHexagonState, hex_llsc_addr, llsc_addr), + CPU_TCG_MAP(CPUHexagonState, hex_llsc_val, llsc_val), + CPU_TCG_MAP(CPUHexagonState, hex_llsc_val_i64, llsc_val_i64), =20 #ifndef CONFIG_USER_ONLY - for (i =3D 0; i < NUM_GREGS; i++) { - hex_greg[i] =3D tcg_global_mem_new_i32(tcg_env, - offsetof(CPUHexagonState, greg[i]), - hexagon_gregnames[i]); - } - for (i =3D 0; i < NUM_SREGS; i++) { - if (i < HEX_SREG_GLB_START) { - hex_t_sreg[i] =3D tcg_global_mem_new_i32(tcg_env, - offsetof(CPUHexagonState, t_sreg[i]), - hexagon_sregnames[i]); - } - } + CPU_TCG_MAP(CPUHexagonState, hex_cause_code, cause_code), + CPU_TCG_MAP(CPUHexagonState, hex_cycle_count, t_cycle_count), + CPU_TCG_MAP_ARRAY(CPUHexagonState, hex_greg, greg, hexagon_gregnames), + CPU_TCG_MAP_ARRAY(CPUHexagonState, hex_t_sreg, t_sreg, hexagon_sregnam= es), #endif - for (i =3D 0; i < TOTAL_PER_THREAD_REGS; i++) { - hex_gpr[i] =3D tcg_global_mem_new(tcg_env, - offsetof(CPUHexagonState, gpr[i]), - hexagon_regnames[i]); - } - hex_new_value_usr =3D tcg_global_mem_new(tcg_env, - offsetof(CPUHexagonState, new_value_usr), "new_value_usr"); - hex_next_PC =3D tcg_global_mem_new(tcg_env, - offsetof(CPUHexagonState, next_PC), "next_PC"); =20 - for (i =3D 0; i < NUM_PREGS; i++) { - hex_pred[i] =3D tcg_global_mem_new(tcg_env, - offsetof(CPUHexagonState, pred[i]), - hexagon_prednames[i]); - } - hex_slot_cancelled =3D tcg_global_mem_new(tcg_env, - offsetof(CPUHexagonState, slot_cancelled), "slot_cancelled"); - hex_llsc_addr =3D tcg_global_mem_new(tcg_env, - offsetof(CPUHexagonState, llsc_addr), "llsc_addr"); - hex_llsc_val =3D tcg_global_mem_new(tcg_env, - offsetof(CPUHexagonState, llsc_val), "llsc_val"); - hex_llsc_val_i64 =3D tcg_global_mem_new_i64(tcg_env, - offsetof(CPUHexagonState, llsc_val_i64), "llsc_val_i64"); -#ifndef CONFIG_USER_ONLY - hex_cause_code =3D tcg_global_mem_new_i32(tcg_env, - offsetof(CPUHexagonState, cause_code), "cause_code"); - hex_cycle_count =3D tcg_global_mem_new_i64(tcg_env, - offsetof(CPUHexagonState, t_cycle_count), "t_cycle_count"); -#endif - for (i =3D 0; i < STORES_MAX; i++) { - snprintf(store_addr_names[i], NAME_LEN, "store_addr_%d", i); - hex_store_addr[i] =3D tcg_global_mem_new(tcg_env, - offsetof(CPUHexagonState, mem_log_stores[i].va), - store_addr_names[i]); + /* Logging stores */ + CPU_TCG_MAP_ARRAY_OF_STRUCTS(CPUHexagonState, hex_store_addr, + mem_log_stores, va, store_addr_names_= ptr), + CPU_TCG_MAP_ARRAY_OF_STRUCTS(CPUHexagonState, hex_store_width, + mem_log_stores, width, store_width_names= _ptr), + CPU_TCG_MAP_ARRAY_OF_STRUCTS(CPUHexagonState, hex_store_val32, + mem_log_stores, data32, store_val32_names= _ptr), + CPU_TCG_MAP_ARRAY_OF_STRUCTS(CPUHexagonState, hex_store_val64, + mem_log_stores, data64, store_val64_names= _ptr), +}; =20 - snprintf(store_width_names[i], NAME_LEN, "store_width_%d", i); - hex_store_width[i] =3D tcg_global_mem_new_i32(tcg_env, - offsetof(CPUHexagonState, mem_log_stores[i].width), - store_width_names[i]); +size_t tcg_global_mapping_count =3D ARRAY_SIZE(tcg_global_mappings); =20 +static void init_cpu_reg_names(void) { + /* + * Create register names and store them in `*_names`, + * then copy to and array of pointers in `*_names_ptr` + * which is easier to pass around. + */ + for (int i =3D 0; i < STORES_MAX; ++i) { + snprintf(store_addr_names[i], NAME_LEN, "store_addr_%d", i); + snprintf(store_width_names[i], NAME_LEN, "store_width_%d", i); snprintf(store_val32_names[i], NAME_LEN, "store_val32_%d", i); - hex_store_val32[i] =3D tcg_global_mem_new(tcg_env, - offsetof(CPUHexagonState, mem_log_stores[i].data32), - store_val32_names[i]); - snprintf(store_val64_names[i], NAME_LEN, "store_val64_%d", i); - hex_store_val64[i] =3D tcg_global_mem_new_i64(tcg_env, - offsetof(CPUHexagonState, mem_log_stores[i].data64), - store_val64_names[i]); + store_addr_names_ptr[i] =3D store_addr_names[i]; + store_width_names_ptr[i] =3D store_width_names[i]; + store_val32_names_ptr[i] =3D store_val32_names[i]; + store_val64_names_ptr[i] =3D store_val64_names[i]; } +} + +void hexagon_translate_init(void) +{ + int i; + + opcode_init(); + for (i =3D 0; i < VSTORES_MAX; i++) { snprintf(vstore_addr_names[i], NAME_LEN, "vstore_addr_%d", i); hex_vstore_addr[i] =3D tcg_global_mem_new(tcg_env, @@ -1415,4 +1407,7 @@ void hexagon_translate_init(void) offsetof(CPUHexagonState, vstore_pending[i]), vstore_pending_names[i]); } + + init_cpu_reg_names(); + init_cpu_tcg_mappings(tcg_global_mappings, tcg_global_mapping_count); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381029; cv=none; d=zohomail.com; s=zohoarc; b=lZLthmCuH2RcZy2dGCIA8yaV9haVcfJbNT3quVk/cdHBVHF+xiAT2gz4wnf4JfOpHJ3puWbHgUTVTPJup3IpGIl3zNYVRUPO//DIm8kMtRQ1VEvzhLwqUF8VxoNmqrHovamxEYSfXB3X/JYJH36VAX5UVSVn7Soanc8xSazBLm4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381029; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=oWTEaYXQxpRItWUabqutlQLWl0zXpXcytDPQMcBKGyw=; b=P60HxSc8/XTuAWjgNuZWOgOrxUwUIDlKw7d26+DvO2+3O5/uQ6LEyECnHkqW8/LkK9By8gZ4TFlAbn+ouAIAFNBeV+GAr6FlfR9lNwACS3Y/+LUSVxHH8yGCDAXDlTiYdL8u68sJ02ZPkJzoAgjgR1TcLWcLlyHaNi7uokhaA4Q= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381029137197.63995028968407; Wed, 29 Jul 2026 20:10:29 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7g-0005Jb-0R; Wed, 29 Jul 2026 23:07:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7N-0004iR-E9 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:36 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7J-00031t-T4 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:32 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=oWTEaYXQxpRItWUabqutlQLWl0zXpXcytDPQMcBKGyw=; b=Wo3MPBon0cnUXTC Nj9T+1TE77RV6iws1K/Ov8D/ORO4jihyJsSP5LfEWvR8pPzJ1k3NH01w2K4pGLJXb8U1RDoHUZLMX /3/fWZrJhQzfQ1BSWFMlyWWTEDv6MctpzTN0xkgfXYO2Vc88XXV01OfhZt3sFhiqbGlNsq14IXDqb vM=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 44/50] target/hexagon: Keep gen_slotval/check_noshuf for helper-to-tcg Date: Thu, 30 Jul 2026 05:10:18 +0200 Message-ID: <20260730031025.12926-45-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381029658158500 Content-Type: text/plain; charset="utf-8" Makes sure gen_slotval() and check_noshuf() remains defined when helper-to-tcg and idef-parser are both used. gen_slotval() is needed for creating a TCGv of the slot value fed to helpers (generated helper-to-tcg code), and check_noshuf() is needed for helper definitions used as input to helper-to-tcg. Signed-off-by: Anton Johansson --- target/hexagon/genptr.c | 2 +- target/hexagon/op_helper.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 3f31037709..5acf237bf0 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -533,7 +533,7 @@ static inline void gen_store_conditional8(DisasContext = *ctx, tcg_gen_movi_tl(hex_llsc_addr, ~0); } =20 -#ifndef CONFIG_HEXAGON_IDEF_PARSER +#if !defined(CONFIG_HEXAGON_IDEF_PARSER) || defined(TARGET_HELPER_TO_TCG) static TCGv gen_slotval(DisasContext *ctx) { int slotval =3D diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 3ce223caba..1a067cd1ce 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -488,7 +488,7 @@ void HELPER(probe_pkt_scalar_hvx_stores)(CPUHexagonStat= e *env, int mask) } } =20 -#ifndef CONFIG_HEXAGON_IDEF_PARSER +#if !defined(CONFIG_HEXAGON_IDEF_PARSER) || defined(CONFIG_HELPER_TO_TCG) /* * mem_noshuf * Section 5.5 of the Hexagon V67 Programmer's Reference Manual --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381128; cv=none; d=zohomail.com; s=zohoarc; b=DfkRaOuh0SwF5O7gOahX6lfynZxa3UQ7D7EnUWaEHuSTxRuwADunYEvBWDwBo26Qp8rxMMVaGxfmvcL98ImrdkK3ihtHduwnDvmw+JpuqTASK4aF8r9XX1a5m9yV1tc7irZWzsQN8pinsxdElm0Gy96Hu2jdWClnn0JCEFJCIvI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381128; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=LWbK1ogEKI4l0O6ZYb7uczyO2GYhf+0xCu+Lx1buNeQ=; b=b6XcF6tzowuzKxtjmMUz3CbpKDMdro26/lr6c4hpoqO8O7OWdlGNfYXNXpebvDjuh4YyETZSGPyMvC9o/f8w1cvCJMRRk0ZSmAsQe+T0shxt45IG0Z1IOASeNsHYdxK0YbpMADj7H0XXpWc/9zc/AqtMiJLuVvx/mgemEne+0DE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381128392798.2861275775197; Wed, 29 Jul 2026 20:12:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7e-0005DT-Qb; Wed, 29 Jul 2026 23:07:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7P-0004jL-8w for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:38 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7L-000322-N9 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:34 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=LWbK1ogEKI4l0O6ZYb7uczyO2GYhf+0xCu+Lx1buNeQ=; b=eC4XQHX8rJvHT/E HwiQuYdpsnjZd7FnNu52ZwfzUIRX6CDYEKTflHIYVqhMd4g9klqTezntGETzCwe0Yo4DyFYIOoddu QeDriLo3qLgjQlbTVRjoVBEqPoXL0N5Ifdq6tkyCSf6FBkpeNTOl9nfAcMnanIZ2eDjjYTymHn/5b Zs=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 45/50] target/hexagon: Emit annotations for helpers Date: Thu, 30 Jul 2026 05:10:19 +0200 Message-ID: <20260730031025.12926-46-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381130268158500 Content-Type: text/plain; charset="utf-8" Adds the following LLVM_ANNOTATE attributes to helper functions generated by Hexagon: 1. "helper-to-tcg", to specify that a given helper functions should be translated, and; 2. "immediate: ..." to make sure immediate arguments to helper functions remain immediates in the emitted TCG code (e.g. slot). 3. "ptr-to-offset: ..." to make sure pointer arguments are treated as immediates representing an offset into the CPU state, needed to work with gvec. Two functions are also added to hex_common.py, to firstly parse the generated file containing all successfully translated helper functions, and secondly to expose the indices of immediate and pointer (vector) arguments to helper functions. The latter is needed to generate the input of helper-to-tcg. Signed-off-by: Anton Johansson --- target/hexagon/gen_helper_funcs.py | 17 ++++++++++- target/hexagon/gen_helper_protos.py | 2 +- target/hexagon/gen_tcg_funcs.py | 2 +- target/hexagon/hex_common.py | 45 +++++++++++++++++++++++------ 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/target/hexagon/gen_helper_funcs.py b/target/hexagon/gen_helper= _funcs.py index 1629ebc0e1..7a3de21019 100755 --- a/target/hexagon/gen_helper_funcs.py +++ b/target/hexagon/gen_helper_funcs.py @@ -41,9 +41,23 @@ def gen_helper_function(f, tag, tagregs, tagimms): ret_type =3D hex_common.helper_ret_type(tag, regs).func_arg =20 declared =3D [] - for arg in hex_common.helper_args(tag, regs, imms): + helper_args, imm_inds, hvx_inds =3D hex_common.helper_args(tag, regs, = imms) + for arg in helper_args: declared.append(arg.func_arg) =20 + ## Specify that helpers should be translated by helper-to-tcg + f.write(f'QEMU_ANNOTATE("helper-to-tcg")\n') + ## Specify which arguments to the helper function should be treated as + ## immediate arguments + if len(imm_inds) > 0: + imm_inds_str =3D ','.join(str(i) for i in imm_inds) + f.write(f'QEMU_ANNOTATE("immediate: {imm_inds_str}")\n') + ## Specify which arguments to the helper function should be treated as + ## gvec vectors + if len(hvx_inds) > 0: + hvx_inds_str =3D ','.join(str(i) for i in hvx_inds) + f.write(f'QEMU_ANNOTATE("ptr-to-offset: {hvx_inds_str}")\n') + arguments =3D ", ".join(declared) f.write(f"{ret_type} HELPER({tag})({arguments})\n") f.write("{\n") @@ -51,6 +65,7 @@ def gen_helper_function(f, tag, tagregs, tagimms): f.write(hex_common.code_fmt(f"""\ uint32_t EA; """)) + ## Declare the return variable if not hex_common.is_predicated(tag): for regtype, regid in regs: diff --git a/target/hexagon/gen_helper_protos.py b/target/hexagon/gen_helpe= r_protos.py index 59c8bdd05c..769611e56c 100755 --- a/target/hexagon/gen_helper_protos.py +++ b/target/hexagon/gen_helper_protos.py @@ -36,7 +36,7 @@ def gen_helper_prototype(f, tag, tagregs, tagimms): ret_type =3D hex_common.helper_ret_type(tag, regs).proto_arg declared.append(ret_type) =20 - for arg in hex_common.helper_args(tag, regs, imms): + for arg in hex_common.helper_args(tag, regs, imms)[0]: declared.append(arg.proto_arg) =20 arguments =3D ", ".join(declared) diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs= .py index 6d5d99cee3..42b0064131 100755 --- a/target/hexagon/gen_tcg_funcs.py +++ b/target/hexagon/gen_tcg_funcs.py @@ -100,7 +100,7 @@ def gen_tcg_func(f, tag, regs, imms): if ret_type !=3D "void": declared.append(ret_type) =20 - for arg in hex_common.helper_args(tag, regs, imms): + for arg in hex_common.helper_args(tag, regs, imms)[0]: declared.append(arg.call_arg) =20 arguments =3D ", ".join(declared) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index d91a653c3d..3809749dfa 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -32,6 +32,7 @@ tags =3D [] # list of all tags overrides =3D {} # tags with helper overrides idef_parser_enabled =3D {} # tags enabled for idef-parser +helper_to_tcg_enabled =3D {} # tags enabled for helper-to-tcg =20 =20 def is_sysemu_tag(tag): @@ -307,6 +308,10 @@ def is_idef_parser_enabled(tag): return tag in idef_parser_enabled =20 =20 +def is_helper_to_tcg_enabled(tag): + return tag in helper_to_tcg_enabled + + def is_hvx_insn(tag): return "A_CVI" in attribdict[tag] =20 @@ -349,6 +354,13 @@ def read_idef_parser_enabled_file(name): idef_parser_enabled =3D set(lines) =20 =20 +def read_helper_to_tcg_enabled_file(name): + global helper_to_tcg_enabled + with open(name, "r") as helper_to_tcg_enabled_file: + lines =3D helper_to_tcg_enabled_file.read().strip().split("\n") + helper_to_tcg_enabled =3D set(lines) + + def is_predicated(tag): return "A_CONDEXEC" in attribdict[tag] =20 @@ -433,7 +445,7 @@ def hvx_off(self): def helper_proto_type(self): return "ptr" def helper_arg_type(self): - return "void *" + return "void * restrict" def helper_arg_name(self): return f"{self.reg_tcg()}_void" =20 @@ -767,7 +779,7 @@ def decl_tcg(self, f, tag, regno): const intptr_t {self.hvx_off()} =3D {vreg_offset_func(tag)}(ctx, {self.reg_num}, 1, true); """)) - if not skip_qemu_helper(tag): + if not skip_qemu_helper(tag) and not is_helper_to_tcg_enabled(tag): f.write(code_fmt(f"""\ TCGv_ptr {self.reg_tcg()} =3D tcg_temp_new_ptr(); tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off(= )}); @@ -792,7 +804,7 @@ def decl_tcg(self, f, tag, regno): f.write(code_fmt(f"""\ const intptr_t {self.hvx_off()} =3D vreg_src_off(ctx, {self.re= g_num}); """)) - if not skip_qemu_helper(tag): + if not skip_qemu_helper(tag) and not is_helper_to_tcg_enabled(tag): f.write(code_fmt(f"""\ TCGv_ptr {self.reg_tcg()} =3D tcg_temp_new_ptr(); tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off(= )}); @@ -833,7 +845,7 @@ def decl_tcg(self, f, tag, regno): vreg_src_off(ctx, {self.reg_num}), sizeof(MMVector), sizeof(MMVector)); """)) - if not skip_qemu_helper(tag): + if not skip_qemu_helper(tag) and not is_helper_to_tcg_enabled(tag): f.write(code_fmt(f"""\ TCGv_ptr {self.reg_tcg()} =3D tcg_temp_new_ptr(); tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off(= )}); @@ -862,7 +874,7 @@ def decl_tcg(self, f, tag, regno): f.write(code_fmt(f"""\ const intptr_t {self.hvx_off()} =3D offsetof(CPUHexagonState, = vtmp); """)) - if not skip_qemu_helper(tag): + if not skip_qemu_helper(tag) and not is_helper_to_tcg_enabled(tag): f.write(code_fmt(f"""\ TCGv_ptr {self.reg_tcg()} =3D tcg_temp_new_ptr(); tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off(= )}); @@ -898,7 +910,7 @@ def decl_tcg(self, f, tag, regno): const intptr_t {self.hvx_off()} =3D {vreg_offset_func(tag)}(ctx, {self.reg_num}, 2, true); """)) - if not skip_qemu_helper(tag): + if not skip_qemu_helper(tag) and not is_helper_to_tcg_enabled(tag): f.write(code_fmt(f"""\ TCGv_ptr {self.reg_tcg()} =3D tcg_temp_new_ptr(); tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off(= )}); @@ -930,7 +942,7 @@ def decl_tcg(self, f, tag, regno): vreg_src_off(ctx, {self.reg_num} ^ 1), sizeof(MMVector), sizeof(MMVector)); """)) - if not skip_qemu_helper(tag): + if not skip_qemu_helper(tag) and not is_helper_to_tcg_enabled(tag): f.write(code_fmt(f"""\ TCGv_ptr {self.reg_tcg()} =3D tcg_temp_new_ptr(); tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off(= )}); @@ -957,7 +969,7 @@ def decl_tcg(self, f, tag, regno): vreg_src_off(ctx, {self.reg_num} ^ 1), sizeof(MMVector), sizeof(MMVector)); """)) - if not skip_qemu_helper(tag): + if not skip_qemu_helper(tag) and not is_helper_to_tcg_enabled(tag): f.write(code_fmt(f"""\ TCGv_ptr {self.reg_tcg()} =3D tcg_temp_new_ptr(); tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off(= )}); @@ -1280,8 +1292,13 @@ def helper_ret_type(tag, regs): raise Exception("numscalarresults > 1") return return_type =20 + def helper_args(tag, regs, imms): args =3D [] + # Used to ensure immediates are passed translated as immediates by + # helper-to-tcg. + imm_indices =3D [] + hvx_indices =3D [] =20 ## First argument is the CPU state if need_env(tag): @@ -1302,16 +1319,20 @@ def helper_args(tag, regs, imms): for regtype, regid in regs: reg =3D get_register(tag, regtype, regid) if reg.is_written() and reg.is_hvx_reg(): + hvx_indices.append(len(args)) args.append(reg.helper_arg()) =20 ## Pass the source registers for regtype, regid in regs: reg =3D get_register(tag, regtype, regid) if reg.is_read() and not (reg.is_hvx_reg() and reg.is_readwrite()): + if reg.is_hvx_reg(): + hvx_indices.append(len(args)) args.append(reg.helper_arg()) =20 ## Pass the immediates for immlett, bits, immshift in imms: + imm_indices.append(len(args)) args.append(HelperArg( "s32", f"tcg_constant_tl({imm_name(immlett)})", @@ -1320,24 +1341,28 @@ def helper_args(tag, regs, imms): =20 ## Other stuff the helper might need if need_pkt_has_multi_cof(tag): + imm_indices.append(len(args)) args.append(HelperArg( "i32", "tcg_constant_tl(ctx->pkt.pkt_has_multi_cof)", "uint32_t pkt_has_multi_cof" )) if need_pkt_need_commit(tag): + imm_indices.append(len(args)) args.append(HelperArg( "i32", "tcg_constant_tl(ctx->need_commit)", "uint32_t pkt_need_commit" )) if need_PC(tag): + imm_indices.append(len(args)) args.append(HelperArg( "i32", "tcg_constant_tl(ctx->pkt.pc)", "target_ulong PC" )) if need_next_PC(tag): + imm_indices.append(len(args)) args.append(HelperArg( "i32", "tcg_constant_tl(ctx->next_PC)", @@ -1356,18 +1381,20 @@ def helper_args(tag, regs, imms): "uint32_t SP" )) if need_slot(tag): + imm_indices.append(len(args)) args.append(HelperArg( "i32", "gen_slotval(ctx)", "uint32_t slotval" )) if need_part1(tag): + imm_indices.append(len(args)) args.append(HelperArg( "i32", "tcg_constant_tl(insn->part1)" "uint32_t part1" )) - return args + return args, imm_indices, hvx_indices =20 =20 def parse_common_args(desc): --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381001; cv=none; d=zohomail.com; s=zohoarc; b=I4O728E5RRUmw+bVYbamdGb2FYqVHWFf+sHGtkMyEaHe7ENW9z1hWXQrZcgrXNYksJXgbDWaHA0hKDXbQ70tLm6cj4a0GfNaTiY8TOkpGRyp+hA4JMqCv1nkxY4d66DCYXakc1NMvf+z0UHOZSulcz589//gHeZWcAo1jFtmTUc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381001; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=g3rR72cUu4RAZYghnI33FnwuTTm+/4Uy8+WhyZsLQnw=; b=Z5RPq0RyoUoVVC5DgSfH9kYnLhtNNwQmrY/UZa51bEc7CxW/QpxtO/i8NGs3BP0Qm5A2rPgdYL17wi7eckWeSS/ck/qiXyMMsPzCIHZxC1Gen6dtYofZV3gNvEi8C/IHSsEIO+KYVOIwDGPVG7ZMxGxJ/Wk0lqW8tfr8+0cAOsQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381001581735.4044287851592; Wed, 29 Jul 2026 20:10:01 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7e-0005BT-By; Wed, 29 Jul 2026 23:07:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7P-0004jM-Bk for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:38 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7N-000329-V3 for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:35 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=g3rR72cUu4RAZYghnI33FnwuTTm+/4Uy8+WhyZsLQnw=; b=orradDewPeiSYnV vSpobLq7bpQEpTQSnsSfxFFq8CaU5aHEEK26LxBxkamEz3XWLY1vYHYTCvjKbA0E19CgtFAGaXmkD 9TLr5UcF+fphdh5T7tD2kLMagU7bcnrrM3tZXF1r5xeKtGIrHNmYPfgAnTYorDWBKJh4p3GCaAbJ+ uU=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 46/50] target/hexagon: Split probe_and_commit helper Date: Thu, 30 Jul 2026 05:10:20 +0200 Message-ID: <20260730031025.12926-47-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381003572158500 Content-Type: text/plain; charset="utf-8" Split function into a slowpath such that the faster function can be translated by helper-to-tcg. Signed-off-by: Anton Johansson Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- target/hexagon/helper.h | 1 + target/hexagon/op_helper.c | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index 033e5619d6..74d5b7ffe8 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -107,6 +107,7 @@ DEF_HELPER_4(probe_noshuf_load, void, env, i32, int, in= t) DEF_HELPER_2(probe_pkt_scalar_store_s0, void, env, int) DEF_HELPER_2(probe_hvx_stores, void, env, int) DEF_HELPER_2(probe_pkt_scalar_hvx_stores, void, env, int) +DEF_HELPER_4(probe_and_commit, void, env, i32, s32, i64) =20 #if !defined(CONFIG_USER_ONLY) DEF_HELPER_3(raise_stack_overflow, void, env, i32, i32) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 1a067cd1ce..c175cecb71 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -488,7 +488,8 @@ void HELPER(probe_pkt_scalar_hvx_stores)(CPUHexagonStat= e *env, int mask) } } =20 -#if !defined(CONFIG_HEXAGON_IDEF_PARSER) || defined(CONFIG_HELPER_TO_TCG) +#if !defined(CONFIG_HEXAGON_IDEF_PARSER) || defined(TARGET_HELPER_TO_TCG) + /* * mem_noshuf * Section 5.5 of the Hexagon V67 Programmer's Reference Manual @@ -500,8 +501,18 @@ static void check_noshuf(CPUHexagonState *env, bool pk= t_has_scalar_store_s1, uint32_t slot, target_ulong vaddr, int size, uintptr_t ra) { - if (slot =3D=3D 0 && pkt_has_scalar_store_s1 && - ((env->slot_cancelled & (1 << 1)) =3D=3D 0)) { + if (slot =3D=3D 0 && pkt_has_scalar_store_s1) { + helper_probe_and_commit(env, vaddr, size, ra); + } +} + +/* + * + */ +void HELPER(probe_and_commit)(CPUHexagonState *env, target_ulong vaddr, + int size, uintptr_t ra) +{ + if ((env->slot_cancelled & (1 << 1)) =3D=3D 0) { probe_read(env, vaddr, size, MMU_USER_IDX, ra); commit_store(env, 1, ra); } --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381114; cv=none; d=zohomail.com; s=zohoarc; b=NlOVFEuzBh5xpu5/pBADrboE+Ty0eOv1t+kbNZ2ZWLpUjgUZTOpL1oRgAZGnixDZpysSrwNjrWEyhvf5YpJnrdj2mt4dkdVaDmvOLlG4IhQAbnXI7GgpcA0gxsqwU9S3gWZJ3XCPFBWR4rO3AXEQBxVdzdBwMgpVt4FNrcEUqLI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381114; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=Zv7NYeayKikcDdOY1xslOcV3UWVEL8WWqscoRbqh03E=; b=EPaEAHsm2ZQMK/+CqPJyQnxY8omSJesnSI8+Uwwaz+nnM/vWvQL3XJKjSWU4fcDCJ3583I0oHta4mv/wyOdQxul7K5/p1QboXmhImwymh2lcBGSFLveyiezJOAhzA7vVOp6bkAJmmPxQm+fMR8hbhUpiWxy0jKjQTOiRoxgfoFA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381113969631.9672927272102; Wed, 29 Jul 2026 20:11:53 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7f-0005FR-Dv; Wed, 29 Jul 2026 23:07:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7R-0004kD-Go for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:38 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7P-00032p-7B for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:36 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=Zv7NYeayKikcDdOY1xslOcV3UWVEL8WWqscoRbqh03E=; b=VL3XO2k8WZr7Bwl 3Ik2y+Kn5RLXh+I1BjN+Gjc9eZKE3fRTD1SWGLeJ2bpRXWIClPNDDDn9tPUDklhXhVXejjnNA+J8k rbsjefw8NXQotKU8tYImepWKdITD6RhD+RUvaq8zKvOHWLZC9DO/ad9CvIuhy2Jvd6vx0BLZf9Ydw fk=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 47/50] target/hexagon: Use helper-to-tcg helper calls Date: Thu, 30 Jul 2026 05:10:21 +0200 Message-ID: <20260730031025.12926-48-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381116039158500 Content-Type: text/plain; charset="utf-8" Replaces the default "helper-gen.h" header with those provided by helper-to-tcg. `gen_helper_*()` definitions are generated for all helpers in the input module, regardless of whether they successfully translated or not. The generated `gen_helper_*()` calls into either `emit_*()` or `tcg_gen_callN` depending on whether translation of that helper was successful or not. Signed-off-by: Anton Johansson --- target/hexagon/genptr.c | 4 ++++ target/hexagon/helper.h | 8 ++++++++ target/hexagon/translate.c | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 5acf237bf0..d99580e815 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -20,7 +20,11 @@ #include "internal.h" #include "tcg/tcg-op.h" #include "tcg/tcg-op-gvec.h" +#if defined(TARGET_HELPER_TO_TCG) +#include "helper-to-tcg-emitted.h" +#else #include "exec/helper-gen.h" +#endif #include "insn.h" #include "opcodes.h" #include "sys_macros.h" diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index 74d5b7ffe8..1796ef7144 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -133,3 +133,11 @@ DEF_HELPER_1(resched, void, env) DEF_HELPER_3(modify_ssr, void, env, i32, i32) DEF_HELPER_1(pending_interrupt, void, env) #endif + +/* + * Include generated helper-to-tcg support helpers, but not during IR + * generation since they won't have been emitted at that point. + */ +#if defined(TARGET_HELPER_TO_TCG) && !defined(HELPER_TO_TCG_IR_GEN) +# include "helper-to-tcg-support-helpers.h" +#endif diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 870475010b..ab6e100a38 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -20,7 +20,15 @@ #include "cpu.h" #include "tcg/tcg-op.h" #include "tcg/tcg-op-gvec.h" +/* + * Include generated gen_helper_*() definitions if using helper-to-tcg, but + * only when not generating input IR since the header won't exist at that = point. + */ +#if defined(TARGET_HELPER_TO_TCG) && !defined(HELPER_TO_TCG_IR_GEN) +#include "helper-to-tcg-emitted.h" +#else #include "exec/helper-gen.h" +#endif #include "exec/helper-proto.h" #include "exec/translation-block.h" #include "accel/tcg/cpu-ldst.h" --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381118; cv=none; d=zohomail.com; s=zohoarc; b=nD1/asbYNYiaEBjqEh4YXjlJRvaBjfiiyrAslAYDgSpm5/Q47rzND2qqwe55OBDZb6iM5r87K/QB+aQtFKqlEZU4wLP0MnZuCCZSNsPd/KKJIi6ZoKmBHKk933nenieDXo2Q+LtIByeMEPu65q/EJy5yaZL5fwXlCLQaiMFxiiA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381118; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=0Wtxg1/Uax0r4CmxZajibuRuo8XlBt8dd5sMz+wH+Uc=; b=d/7Hn+Sk+e/BYgmAjVzg5mEoMWqAzdex4vEdv5OABw/i1qI4EM4KSTfOzxMi+0bTpGAc6PVvyI9aN9hi8yhj2ByMQBRJdzF+5T2GO/Cscygm8VQMsAQGYqUhr/ekt3AlBYlQenTqc97DpK1/uB5+/uGDoFIM46842naW5ZC7Hlo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381118530591.890054985053; Wed, 29 Jul 2026 20:11:58 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7j-0005gX-8X; Wed, 29 Jul 2026 23:07:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7U-0004oJ-6b for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:40 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7R-000331-Ij for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=0Wtxg1/Uax0r4CmxZajibuRuo8XlBt8dd5sMz+wH+Uc=; b=WZ4BUWtPxqI5Glh 9LMVJPi2873joDwov/2SWR5RNhbQnjb0O11WJTdhwqqdVpFy5Jmg5ATn7JaS9abW1zEgVQsg6k/Pf +Mj7NGP5Y0lkTQ0Z7zbtjeWPTnY1BfcJ/UztuWY8I4QUJgKLagLZeso2HOSYoVCBMSxDx+JqO6G93 Jk=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 48/50] target/hexagon: Manually call generated HVX instructions Date: Thu, 30 Jul 2026 05:10:22 +0200 Message-ID: <20260730031025.12926-49-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381120056158500 Content-Type: text/plain; charset="utf-8" For HVX instructions that were successfully translated by helper-to-tcg, emit calls to emit_*() "manually" from generate_*(). Recall that scalar instructions translated by helper-to-tcg are automatically called by a hook in tcg_gen_callN. Signed-off-by: Anton Johansson --- target/hexagon/gen_tcg_funcs.py | 14 ++++++++ target/hexagon/hex_common.py | 58 +++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs= .py index 42b0064131..ee3b183e7b 100755 --- a/target/hexagon/gen_tcg_funcs.py +++ b/target/hexagon/gen_tcg_funcs.py @@ -86,7 +86,21 @@ def gen_tcg_func(f, tag, regs, imms): =20 arguments =3D ", ".join(["ctx", "ctx->insn", "&ctx->pkt"] + declar= ed) f.write(f" emit_{tag}({arguments});\n") + elif hex_common.is_helper_to_tcg_enabled(tag) and tag.startswith("V6_"= ): + ## For vector functions translated by helper-to-tcg we need to + ## manually call the emitted code. All other instructions transla= ted + ## are automatically called by the helper-functions dispatcher in + ## tcg_gen_callN. + declared =3D [] + ## Handle registers + ret_type =3D hex_common.helper_ret_type(tag, regs).call_arg + if ret_type !=3D "void": + declared.append(ret_type) + for arg in hex_common.helper_to_tcg_hvx_call_args(tag, regs, imms): + declared.append(arg) =20 + arguments =3D ", ".join(declared) + f.write(f" emit_{tag}({arguments});\n") elif hex_common.skip_qemu_helper(tag): if "A_FPOP" in hex_common.attribdict[tag]: f.write(" TCGv pkt_need_commit =3D ") diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 3809749dfa..59fd563923 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -1293,6 +1293,60 @@ def helper_ret_type(tag, regs): return return_type =20 =20 +def helper_to_tcg_hvx_call_args(tag, regs, imms): + args =3D [] + # Used to ensure immediates are passed translated as immediates by + # helper-to-tcg. + imm_indices =3D [] + + ## First argument is the CPU state + if need_env(tag): + args.append("tcg_env") + + ## For predicated instructions, we pass in the destination register + if is_predicated(tag): + for regtype, regid in regs: + reg =3D get_register(tag, regtype, regid) + if reg.is_writeonly() and not reg.is_hvx_reg(): + args.append(reg.helper_arg().call_arg) + + ## Pass the HVX destination registers + for regtype, regid in regs: + reg =3D get_register(tag, regtype, regid) + if reg.is_written() and reg.is_hvx_reg(): + args.append(reg.hvx_off()) + + ## Pass the source registers + for regtype, regid in regs: + reg =3D get_register(tag, regtype, regid) + if reg.is_read() and not (reg.is_hvx_reg() and reg.is_readwrite()): + if reg.is_hvx_reg(): + args.append(reg.hvx_off()) + else: + args.append(reg.helper_arg().call_arg) + + ## Pass the immediates + for immlett, bits, immshift in imms: + imm_indices.append(len(args)) + args.append(f"{imm_name(immlett)}") + + ## Other stuff the helper might need + if need_pkt_has_multi_cof(tag): + args.append("ctx->pkt->pkt_has_multi_cof") + if need_pkt_need_commit(tag): + args.append("ctx->need_commit") + if need_PC(tag): + args.append("ctx->pkt->pc") + if need_next_PC(tag): + args.append("ctx->next_PC") + if need_slot(tag): + args.append("gen_slotval(ctx)") + if need_part1(tag): + args.append("insn->part1") + + return args + + def helper_args(tag, regs, imms): args =3D [] # Used to ensure immediates are passed translated as immediates by @@ -1406,6 +1460,8 @@ def parse_common_args(desc): parser.add_argument("out", help=3D"output file") parser.add_argument("--idef-parser", help=3D"file of instructions translated by idef-pa= rser") + parser.add_argument("--helper-to-tcg", + help=3D"file of instructions translated by helper-= to-tcg") args =3D parser.parse_args() read_semantics_file(args.semantics) read_overrides_file(args.overrides) @@ -1413,6 +1469,8 @@ def parse_common_args(desc): read_overrides_file(args.overrides_sys) if args.idef_parser: read_idef_parser_enabled_file(args.idef_parser) + if args.helper_to_tcg: + read_helper_to_tcg_enabled_file(args.helper_to_tcg) calculate_attribs() init_registers() return args --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381107; cv=none; d=zohomail.com; s=zohoarc; b=WGq9btssNdbExk+m8PSke2fL6hEqetrTOhCMw9uK0rN3q64HU8g1SK/DS5G8w27fYRc/7QXA2CoqfNBoi8EV/nlAobpSMouDfB7gpnI+QdgzYreKKJbdyL7qWJOABmL/Hyu9TTK1KK5cG23pCYO3yxbPvbw/MXDuD0W5XnhOGas= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381107; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=CgRS/dIhltOBSTrgSM2uh1yyyoZl/8xCL474UlnGPbo=; b=XdAzYqfAaBujPKrqs26g9MjnDUzrRU1EJxNQyotMzdbWx5eYYFaoBWHYfT2bqPQv5TZv7/ulcW6mXmzxKS/ELqDkag4bpLFZszi1783oR+8fZHD/NvKGle3UaPpo94Brdp0cHKwE3alpy6hOAhoFiARBFxnKr5w7dvqN5XvJDkA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381107868963.780604426005; Wed, 29 Jul 2026 20:11:47 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7f-0005FP-D1; Wed, 29 Jul 2026 23:07:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7T-0004mZ-Tz for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:40 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7S-00033F-Hi for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=CgRS/dIhltOBSTrgSM2uh1yyyoZl/8xCL474UlnGPbo=; b=Nycr6vhUR+UbNRr 56bWx24zikXlJtCkohsaX9YoyedG6kZkDCbSZi1Ay+jPaVc+0gbgIrLqrcfyV08XGuzHOKS+4GtiZ 0trZ7O71cGHMxdGWdtMOY5kEwJFFmZsa66I8wqTYCbi+4dtuWnETtxkX0tMqUnr7hB7ARc7fDCL6G Uo=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 49/50] target/hexagon: Use idef-parser as a fallback Date: Thu, 30 Jul 2026 05:10:23 +0200 Message-ID: <20260730031025.12926-50-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381109975158500 Content-Type: text/plain; charset="utf-8" Only generate input functions to idef-parser for instructions which failed to be translated by helper-to-tcg, and which have no overrides. Signed-off-by: Anton Johansson --- target/hexagon/gen_idef_parser_funcs.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/hexagon/gen_idef_parser_funcs.py b/target/hexagon/gen_i= def_parser_funcs.py index 32bce9b002..6bcc6e4bd0 100644 --- a/target/hexagon/gen_idef_parser_funcs.py +++ b/target/hexagon/gen_idef_parser_funcs.py @@ -49,10 +49,13 @@ def main(): ) parser.add_argument("semantics", help=3D"semantics file") parser.add_argument("out", help=3D"output file") + parser.add_argument("--helper-to-tcg", help=3D"file of instructions tr= anslated by helper-to-tcg") args =3D parser.parse_args() hex_common.read_semantics_file(args.semantics) hex_common.calculate_attribs() hex_common.init_registers() + if args.helper_to_tcg: + hex_common.read_helper_to_tcg_enabled_file(args.helper_to_tcg) tagregs =3D hex_common.get_tagregs() tagimms =3D hex_common.get_tagimms() =20 @@ -62,6 +65,12 @@ def main(): for tag in hex_common.tags: if hex_common.tag_ignore(tag): continue + ## Skip instructions with overrides + if hex_common.skip_qemu_helper(tag): + continue + ## Skip instructions translated by helper-to-tcg + if hex_common.is_helper_to_tcg_enabled(tag): + continue ## Skip the priv instructions if "A_PRIV" in hex_common.attribdict[tag]: continue --=20 2.52.0 From nobody Mon Sep 28 02:07:46 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1785381131; cv=none; d=zohomail.com; s=zohoarc; b=KLjCB5GojC1WLRw7VLax0jThtO2u6d21H8Wgw+XGOXURxJInViCfyHtuLD+4khRR2oNXHfLhXQj1MKDEUsRQDqXdL/Nseuc236AkbsLbwV1B6WHJzCV1bhr37Gg0vIfnsXAi0ZByNgkq3QXsug0NAyjSboo2wyZpC36dlU1muss= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785381131; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=i+JQrkELf2IFtebI8FAtcNj7KV+AasmxXTEZ+9GznPc=; b=LSTJg3tUHKO4SF17CoL9Ad72QpmWzqq5Ku1XrEr9RkPQjCiS3HFc4cHhLfewwIRb49bdztTN34xWCztiyzzzRLYOMZp+RvY7S7pdZ1CnGinwGcvsjMpbMrPrZ6OiHQhfdm8cJBVW59k2Vf5a8qLP7kfCIZjJ6gMvDjU3luf7x8k= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785381131671275.4480904346407; Wed, 29 Jul 2026 20:12:11 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpH7j-0005gZ-8d; Wed, 29 Jul 2026 23:07:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7Z-0004ut-0v for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:46 -0400 Received: from rev.ng ([94.130.142.21]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpH7V-00033d-0n for qemu-devel@nongnu.org; Wed, 29 Jul 2026 23:07:42 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=rev.ng; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive:List-Unsubscribe:List-Unsubscribe-Post: List-Help; bh=i+JQrkELf2IFtebI8FAtcNj7KV+AasmxXTEZ+9GznPc=; b=dzKfvbV/RoTVnyv lsSuFzRyWV6PsMHsgHTG3jQMNW7rAglL2IN+742BR2Z+4Ktv22xCpscaya9V9fuDfDj/FIhv/+qv2 kWI4Niyu3JSYfAVNgBTUmk3JXU+waBdvtWxRx7a9MZTSPPR6VdJBNOOky6puIegTab6gGIHGNDf5G Z4=; To: qemu-devel@nongnu.org Cc: ale@rev.ng, brian.cain@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, philmd@mailo.com, Anton Johansson Subject: [PATCH v2 50/50] target/hexagon: Use helper-to-tcg Date: Thu, 30 Jul 2026 05:10:24 +0200 Message-ID: <20260730031025.12926-51-anjo@rev.ng> In-Reply-To: <20260730031025.12926-1-anjo@rev.ng> References: <20260730031025.12926-1-anjo@rev.ng> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=94.130.142.21; envelope-from=anjo@rev.ng; helo=rev.ng X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Anton Johansson From: Anton Johansson via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1785381132195158500 Content-Type: text/plain; charset="utf-8" Modifies meson.build to use helper-to-tcg for automatic translation of helper functions. Any helper functions with the "helper-to-tcg" attribute will be automatically translated to TCG. Order of code generation is changed, and helper functions are always generated first, for all instructions. Helper functions are needed as input helper-to-tcg. Next, input to idef-parser is generated for all instructions that were not successfully translated by helper-to-tcg. As such, a majority of instructions will be translated by helper-to-tcg, and the remaining instructions fed through idef-parser can be reduced moving forward. Signed-off-by: Anton Johansson --- configs/targets/hexagon-linux-user.mak | 1 + configs/targets/hexagon-softmmu.mak | 1 + target/hexagon/meson.build | 148 ++++++++++++++++++------- 3 files changed, 110 insertions(+), 40 deletions(-) diff --git a/configs/targets/hexagon-linux-user.mak b/configs/targets/hexag= on-linux-user.mak index 51fde5d60e..d441112f2e 100644 --- a/configs/targets/hexagon-linux-user.mak +++ b/configs/targets/hexagon-linux-user.mak @@ -4,3 +4,4 @@ TARGET_SYSTBL=3Dsyscall.tbl TARGET_SYSTBL_ABI=3Dcommon,32,hexagon,time32,stat64,rlimit,renameat TARGET_LONG_BITS=3D32 TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API=3Dy +TARGET_HELPER_TO_TCG=3Dy diff --git a/configs/targets/hexagon-softmmu.mak b/configs/targets/hexagon-= softmmu.mak index a77c100f0c..bef72e8b2b 100644 --- a/configs/targets/hexagon-softmmu.mak +++ b/configs/targets/hexagon-softmmu.mak @@ -6,3 +6,4 @@ TARGET_LONG_BITS=3D32 TARGET_NOT_USING_LEGACY_LDST_PHYS_API=3Dy TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API=3Dy TARGET_NEED_FDT=3Dy +TARGET_HELPER_TO_TCG=3Dy diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index 59cb09c107..fdacd61ccf 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -262,23 +262,125 @@ hexagon_softmmu_ss.add(files( 'machine.c', )) =20 +helper_dep =3D [semantics_generated] +helper_in =3D [semantics_generated, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_= h] + +# +# Step 5 +# We use Python scripts to generate the following files +# helper_protos_generated.h.inc +# helper_funcs_generated.c.inc +# analyze_funcs_generated.c.inc # -# Step 4.5 +helper_protos_generated =3D custom_target( + 'helper_protos_generated.h.inc', + output: 'helper_protos_generated.h.inc', + depends: helper_dep, + depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h], + command: [python, files('gen_helper_protos.py'), helper_in, '@OUTPUT@'= ], +) +hexagon_ss.add(helper_protos_generated) + +helper_funcs_generated =3D custom_target( + 'helper_funcs_generated.c.inc', + output: 'helper_funcs_generated.c.inc', + depends: helper_dep, + depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h], + command: [python, files('gen_helper_funcs.py'), helper_in, '@OUTPUT@'], +) +hexagon_ss.add(helper_funcs_generated) + +analyze_funcs_generated =3D custom_target( + 'analyze_funcs_generated.c.inc', + output: 'analyze_funcs_generated.c.inc', + depends: helper_dep, + depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h], + command: [python, files('gen_analyze_funcs.py'), helper_in, '@OUTPUT@'= ], +) +hexagon_ss.add(analyze_funcs_generated) + +# +# Step 6 +# If enabled, run helper-to-tcg to attempt to translate any remaining +# helper functions, producing: +# helper-to-tcg-emitted.c +# helper-to-tcg-emitted.h +# helper-to-tcg-enabled +# helper-to-tcg-log +# + +idef_command_extra =3D [] +idef_dep_extra =3D [] +if helper_to_tcg.found() + helper_to_tcg_get_llvm_ir_cmd =3D helper_to_tcg.get_variable('get_llvm= _ir_cmd') + helper_to_tcg_pipeline =3D helper_to_tcg.get_variable('pipeline') + + helper_to_tcg_input_files =3D [ + meson.current_source_dir() / 'op_helper.c', + meson.current_source_dir() / 'translate.c', + meson.current_source_dir() / 'reg_fields.c', + meson.current_source_dir() / 'arch.c', + ] + + ll =3D custom_target('to-ll', + input: helper_to_tcg_input_files, + output:'helper-to-tcg-input.ll', + depends: [helper_funcs_generated, helper_protos_generated, libqemu= util], + command: helper_to_tcg_get_llvm_ir_cmd + ['-o', '@OUTPUT@', '@INPU= T@', '--target-path', 'target/hexagon'] + ) + + helper_to_tcg_target =3D custom_target('helper-to-tcg-hexagon', + output: ['helper-to-tcg-emitted.c', + 'helper-to-tcg-emitted.h', + 'helper-to-tcg-enabled'], + input: [ll], + depends: [helper_to_tcg_pipeline, analyze_funcs_generated, helper_= funcs_generated, helper_protos_generated], + command: [helper_to_tcg_pipeline, + '--temp-vector-block=3Dtmp_VRegs', + '--max-vector-temp-bytes=3D1024', + '--max-vector-instructions=3D16', + '--mmu-index-function=3Dget_tb_mmu_index', + '--tcg-global-mappings=3Dtcg_global_mappings', + '--output-source=3D@OUTPUT0@', + '--output-header=3D@OUTPUT1@', + '--output-enabled=3D@OUTPUT2@', + '@INPUT@'] + ) + + hexagon_ss.add(helper_to_tcg_target) + + # List of instructions for which TCG generation was successful + generated_tcg_list =3D helper_to_tcg_target[2].full_path() + + # Setup dependencies for idef-parser + idef_dep_extra +=3D helper_to_tcg_target + idef_command_extra +=3D ['--helper-to-tcg', generated_tcg_list] + + # Setup input and dependencies for the final step, this depends on whe= ther + helper_dep +=3D [helper_to_tcg_target] + helper_in +=3D ['--helper-to-tcg', generated_tcg_list] +endif + + + +# +# Step 6 # We use flex/bison based idef-parser to generate TCG code for a lot # of instructions. idef-parser outputs # idef-generated-emitter.c # idef-generated-emitter.h.inc # idef-generated-enabled-instructions # + idef_parser_enabled =3D get_option('hexagon_idef_parser') if idef_parser_enabled and ('hexagon-linux-user' in target_dirs or 'hexagon-softmmu' in target_dirs) idef_parser_input_generated =3D custom_target( 'idef_parser_input.h.inc', output: 'idef_parser_input.h.inc', - depends: [semantics_generated], + depends: [semantics_generated] + idef_dep_extra, depend_files: [hex_common_py], - command: [python, files('gen_idef_parser_funcs.py'), semantics_gen= erated, '@OUTPUT@'], + command: [python, files('gen_idef_parser_funcs.py'), semantics_gen= erated, '@OUTPUT@'] + idef_command_extra ) =20 compiler =3D meson.get_compiler('c').cmd_array() @@ -347,40 +449,15 @@ if idef_parser_enabled and ('hexagon-linux-user' in t= arget_dirs or =20 # Setup input and dependencies for the next step, this depends on whet= her or # not idef-parser is enabled - helper_dep =3D [semantics_generated, idef_generated_tcg_c, idef_genera= ted_tcg] - helper_in =3D [semantics_generated, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_= sys_h, '--idef-parser', idef_generated_list] -else - # Setup input and dependencies for the next step, this depends on whet= her or - # not idef-parser is enabled - helper_dep =3D [semantics_generated] - helper_in =3D [semantics_generated, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_= sys_h] + helper_dep +=3D [idef_generated_tcg_c, idef_generated_tcg] + helper_in +=3D ['--idef-parser', idef_generated_list] endif =20 # -# Step 5 +# Step 7 # We use Python scripts to generate the following files -# helper_protos_generated.h.inc -# helper_funcs_generated.c.inc # tcg_funcs_generated.c.inc # -helper_protos_generated =3D custom_target( - 'helper_protos_generated.h.inc', - output: 'helper_protos_generated.h.inc', - depends: helper_dep, - depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h], - command: [python, files('gen_helper_protos.py'), helper_in, '@OUTPUT@'= ], -) -hexagon_ss.add(helper_protos_generated) - -helper_funcs_generated =3D custom_target( - 'helper_funcs_generated.c.inc', - output: 'helper_funcs_generated.c.inc', - depends: helper_dep, - depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h], - command: [python, files('gen_helper_funcs.py'), helper_in, '@OUTPUT@'], -) -hexagon_ss.add(helper_funcs_generated) - tcg_funcs_generated =3D custom_target( 'tcg_funcs_generated.c.inc', output: 'tcg_funcs_generated.c.inc', @@ -390,14 +467,5 @@ tcg_funcs_generated =3D custom_target( ) hexagon_ss.add(tcg_funcs_generated) =20 -analyze_funcs_generated =3D custom_target( - 'analyze_funcs_generated.c.inc', - output: 'analyze_funcs_generated.c.inc', - depends: helper_dep, - depend_files: [hex_common_py, gen_tcg_h, gen_tcg_hvx_h, gen_tcg_sys_h], - command: [python, files('gen_analyze_funcs.py'), helper_in, '@OUTPUT@'= ], -) -hexagon_ss.add(analyze_funcs_generated) - target_arch +=3D {'hexagon': hexagon_ss} target_system_arch +=3D {'hexagon': hexagon_softmmu_ss} --=20 2.52.0