From patchwork Mon Feb 26 14:28:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bhushan Attarde X-Patchwork-Id: 86389 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DDF8B3858C33 for ; Mon, 26 Feb 2024 14:30:09 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mx08-00376f01.pphosted.com (mx08-00376f01.pphosted.com [91.207.212.86]) by sourceware.org (Postfix) with ESMTPS id 68E5B3858C5E for ; Mon, 26 Feb 2024 14:29:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 68E5B3858C5E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=imgtec.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=imgtec.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 68E5B3858C5E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=91.207.212.86 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1708957746; cv=none; b=GL+cey61asiD6qDAMuTUvDulrTDxs6g0GA31rxXptXZ0lfBg1MIBlGM13ujAPl9Nn4GW3fIKn1BrNuBWLWwZxv2rM5rse1wIo1khkSRtgrhbiW1WDKGyq9aWq2+/lar7YTruecZ/fWFZPlfEKSKSmInYWoAkibBZvkC0Tly7WBE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1708957746; c=relaxed/simple; bh=XI9GjWCBhAkBx6JfVnERlIab9hyPvtquo98CspQwB+Q=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Pgt4t1AF1d/QvB04uxBuFuUM77mGcoRcn5F+l9HLbtxgz20QcGixnpA0psiJoGmMyMwTJFZeDZTUJXu4823uAjcp5SeB8syEUPfeZtXEVFezPN7b0kuVtBQlpsTRewpJEkkAwkc4Oz6z5wmpiolHbBwvdGyPeOc47FIm9bYEPjM= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from pps.filterd (m0168888.ppops.net [127.0.0.1]) by mx08-00376f01.pphosted.com (8.17.1.24/8.17.1.24) with ESMTP id 41Q8K02n021970; Mon, 26 Feb 2024 14:28:58 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=imgtec.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s= dk201812; bh=AzKudNCveKfq+8h2QEsH26Ufg4jNkQllaywXOKxIlnI=; b=MvP p7LdncdYC/Y+fsZ+9i3HSCboehzIR0gHp5joDeW14AMFvDM7O5Se556bj9V8QmZr SKWtbPHXe8MRvPVTXn2m8n031Rq+cJPksYW68Sl7qlrd2y5MXdgi0Hbt7mIOus/V uwkzr+7ftFZuR9WiSWwnzh/4LZTCTSqDYewBVQC1tgujAzb9y3xS35Un3RAYjnfn I1oaAR0uD8f1Fi26hfhku6Ss9IJo7zlq3C5IMY+K9xCcYyCOzXsAyg41ZP6P464a aVYTepiUjSjx6w42sJrfEziHKwIBIjI3EnHwxkZFCQKEjtfCzC703SOm558QT3Vo 8F04nwWHoL1MNUvckRA== Received: from hhmail05.hh.imgtec.org ([217.156.249.195]) by mx08-00376f01.pphosted.com (PPS) with ESMTPS id 3wf7kssr7v-3 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Mon, 26 Feb 2024 14:28:58 +0000 (GMT) Received: from hhbattarde.hh.imgtec.org (10.100.136.78) by HHMAIL05.hh.imgtec.org (10.100.10.120) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Mon, 26 Feb 2024 14:28:57 +0000 From: To: CC: , , , Bhushan Attarde Subject: [PATCH 11/11] sim: riscv: Add double precision floating-point conversion instructions Date: Mon, 26 Feb 2024 14:28:45 +0000 Message-ID: <20240226142845.1629113-3-bhushan.attarde@imgtec.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240226142845.1629113-1-bhushan.attarde@imgtec.com> References: <20240226142845.1629113-1-bhushan.attarde@imgtec.com> MIME-Version: 1.0 X-Originating-IP: [10.100.136.78] X-ClientProxiedBy: HHMAIL05.hh.imgtec.org (10.100.10.120) To HHMAIL05.hh.imgtec.org (10.100.10.120) X-EXCLAIMER-MD-CONFIG: 15a78312-3e47-46eb-9010-2e54d84a9631 X-Proofpoint-GUID: -hcoJn_F2XhoQzxTzZ-MR5dXqqOUVp0k X-Proofpoint-ORIG-GUID: -hcoJn_F2XhoQzxTzZ-MR5dXqqOUVp0k X-Spam-Status: No, score=-12.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org From: Bhushan Attarde Added simulation of following single precision floating-point instructions fcvt.w.d, fcvt.wu.d, fcvt.d.w, fcvt.d.wu, fcvt.l.d, fcvt.lu.d, fcvt.d.l, fcvt.d.lu, fcvt.d.s and fcvt.s.d. Added test file sim/testsuite/riscv/d-conversion.s to test these instructions. --- sim/riscv/sim-main.c | 326 +++++++++++++++++++++++++++++ sim/testsuite/riscv/d-conversion.s | 111 ++++++++++ 2 files changed, 437 insertions(+) create mode 100755 sim/testsuite/riscv/d-conversion.s diff --git a/sim/riscv/sim-main.c b/sim/riscv/sim-main.c index e715ca2501e..66e0610c246 100644 --- a/sim/riscv/sim-main.c +++ b/sim/riscv/sim-main.c @@ -1036,6 +1036,77 @@ float32_math (SIM_CPU *cpu, int rd, int rs1, int rs2, } } +/* Round and return the double value. This function is used before we + perform any operation on the input double value. */ +static double +round_double_input (double value, int rm) +{ + double result = value; + if (rm == RNE) + { + double fractional_part = value - trunc (value); + /* Check if the number is halfway between two values. */ + if (fractional_part == 0.5 || fractional_part == -0.5) + { + result = floor (value); + if (fmod (result, 2.0) != 0) + result += (value > 0) ? 1.0 : -1.0; + } + else + result = round (value); + } + else if (rm == RTZ) + result = trunc (value); + else if (rm == RDN) + result = floor (value); + else if (rm == RUP) + result = ceil (value); + else + { + /* No direct match for RMM. Simulate it. */ + double fracPart = value - (int64_t) value; + if (fracPart > 0.5 || fracPart < -0.5) + result = round (value); + else if (fracPart == 0.5) + result = ceil (value); + else if (fracPart == -0.5) + result = floor (value); + else + result = value; + } + return result; +} + +/* Round and return the double value. This function is used after we + perform the operation to get the result rounded. */ +static double +round_double_output (double value, int rm) +{ + double result; + if (rm == RNE) + result = value; + else if (rm == RTZ) + result = trunc (value); + else if (rm == RDN) + result = floor (value); + else if (rm == RUP) + result = ceil (value); + else + { + /* No direct match for RMM. Simulate it. */ + double fracPart = value - (int64_t) value; + if (fracPart > 0.5 || fracPart < -0.5) + result = round (value); + else if (fracPart == 0.5) + result = ceil (value); + else if (fracPart == -0.5) + result = floor (value); + else + result = value; + } + return result; +} + /* Round and return the float value. This function is used before we perform any operation on the input float value. */ static float @@ -1107,6 +1178,183 @@ round_float_output (float value, int rm) return result; } +/* Convert the double precision floating point value into integer. */ +static void +convert_double_to_int (SIM_CPU *cpu, int rd, int rs1, int sign, + int rm, int is_32bit) +{ + struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu); + double src, rounded; + uint64_t rs1_bits; + int iclamp; + uint32_t uclamp; + rs1_bits = (uint64_t) riscv_cpu->fpregs[rs1]; + memcpy (&src, &rs1_bits, sizeof (src)); + + if (rm == DYN) + rm = riscv_cpu->csr.frm; + + /* Get the input rounded. */ + rounded = round_double_input (src, rm); + + if (sign == SIGNED) + { + /* Clamp the input to int32_t range. */ + iclamp = min (max ((int64_t) rounded, INT_MIN), INT_MAX); + if (is_32bit) + store_rd (cpu, rd, (int) iclamp); + else + store_rd (cpu, rd, (int64_t) iclamp); + } + else + { + /* Clamp the input to uint32_t range. */ + uclamp = min (max ((uint64_t) rounded, 0), UINT_MAX); + if (rounded < 0.0f) + uclamp = 0; + if (is_32bit) + store_rd (cpu, rd, (uint32_t) uclamp); + else + store_rd (cpu, rd, (uint64_t) uclamp); + } +} + +/* Convert the double precision floating point value into long integer. */ +static void +convert_double_to_long (SIM_CPU *cpu, int rd, int rs1, int sign, + int rm) +{ + struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu); + double src, rounded; + uint64_t rs1_bits; + int64_t lclamp; + uint64_t luclamp; + rs1_bits = (uint64_t) riscv_cpu->fpregs[rs1]; + memcpy (&src, &rs1_bits, sizeof (src)); + + if (rm == DYN) + rm = riscv_cpu->csr.frm; + + /* Get the input rounded. */ + rounded = round_double_input (src, rm); + + if (sign == SIGNED) + { + /* Clamp the input to int64_t range. */ + lclamp = min (max ((int64_t) rounded, LONG_MIN), LONG_MAX); + store_rd (cpu, rd, (int64_t) lclamp); + } + else + { + /* Clamp the input to uint64_t range. */ + luclamp = min (max ((uint64_t) rounded, 0), ULONG_MAX); + if (rounded < 0.0f) + luclamp = 0; + store_rd (cpu, rd, (uint64_t) luclamp); + } +} + +/* Convert the long integer value into double precision floating point. */ +static void +convert_long_to_double (SIM_CPU *cpu, int rd, int rs1, int sign, + int rm) +{ + struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu); + uint64_t rd_bits; + uint64_t usrc = (uint64_t) riscv_cpu->regs[rs1]; + int64_t isrc = (int64_t) riscv_cpu->regs[rs1]; + double result = .0; + int old_rm; + + if (rm == DYN) + rm = riscv_cpu->csr.frm; + + old_rm = set_riscv_rounding_mode (rm); + + if (rm == RMM) + { + if (sign == SIGNED) + { + if (isrc > 0) + { + fesetround (FE_UPWARD); + result = (double) isrc; + result = ceil (result); + } + else + { + fesetround (FE_DOWNWARD); + result = (double) isrc; + result = floor (result); + } + } + else + { + /* Since it's unsigned, it's always positive. */ + fesetround (FE_UPWARD); + result = (double) usrc; + result = ceil (result); + } + } + else + { + if (sign == SIGNED) + result = (double) isrc; + else + result = (double) usrc; + + /* Get the result rounded. */ + result = round_double_output (result, rm); + } + + /* Restore rounding mode. */ + fesetround (old_rm); + + /* Store the result. */ + memcpy (&rd_bits, &result, sizeof (result)); + store_fp (cpu, rd, rd_bits); +} + +/* Convert the double precision floating point value into single precision. */ +static void +double_to_float (SIM_CPU *cpu, int rd, int rs1, int rm) +{ + struct riscv_sim_cpu *riscv_cpu = RISCV_SIM_CPU (cpu); + double src; + float result = 0; + int old_rm; + uint64_t rs1_bits; + uint32_t rd_bits; + + if (rm == DYN) + rm = riscv_cpu->csr.frm; + + old_rm = set_riscv_rounding_mode (rm); + + rs1_bits = (uint64_t) riscv_cpu->fpregs[rs1]; + memcpy (&src, &rs1_bits, sizeof (src)); + + result = (float) src; + + if (rm == RMM) + { + if (is_float_halfway (result)) + { + if (result > 0) + result = nextafterf (result, INFINITY); + else + result = nextafterf (result, -INFINITY); + } + } + + /* Store result. */ + memcpy (&rd_bits, &result, sizeof (result)); + store_fp (cpu, rd, rd_bits); + + /* Restore rounding mode. */ + fesetround (old_rm); +} + static void convert_float_to_int (SIM_CPU *cpu, int rd, int rs1, int sign, int rm, int is_32bit) @@ -1885,6 +2133,84 @@ execute_d (SIM_CPU *cpu, unsigned_word iw, const struct riscv_opcode *op) case MATCH_FSQRT_D | MASK_RM: float64_math (cpu, rd, rs1, rs2, 0, rm, FSQRT); break; + case MATCH_FCVT_W_D: + case MATCH_FCVT_W_D | MASK_RM: + TRACE_INSN (cpu, "fcvt.w.d %s, %s, rm=%d;", rd_name, rs1_name, rm); + convert_double_to_int (cpu, rd, rs1, SIGNED, rm, 1); + break; + case MATCH_FCVT_WU_D: + case MATCH_FCVT_WU_D | MASK_RM: + TRACE_INSN (cpu, "fcvt.wu.d %s, %s, rm=%d;", rd_name, rs1_name, rm); + convert_double_to_int (cpu, rd, rs1, UNSIGNED, rm, 1); + break; + case MATCH_FCVT_D_W: + case MATCH_FCVT_D_W | MASK_RM: + { + double d; + uint64_t rd_bits; + int32_t isrc; + TRACE_INSN (cpu, "fcvt.d.w %s, %s, rm=%d;", rd_name, rs1_name, rm); + isrc = (int32_t) riscv_cpu->regs[rs1]; + d = (double) isrc; + memcpy (&rd_bits, &d, sizeof (d)); + store_fp (cpu, rd, rd_bits); + break; + } + case MATCH_FCVT_D_WU: + case MATCH_FCVT_D_WU | MASK_RM: + { + double d; + uint64_t rd_bits; + uint32_t usrc; + TRACE_INSN (cpu, "fcvt.d.wu %s, %s, rm=%d;", rd_name, rs1_name, rm); + usrc = (uint32_t) riscv_cpu->regs[rs1]; + d = (double) usrc; + memcpy (&rd_bits, &d, sizeof (d)); + store_fp (cpu, rd, rd_bits); + break; + } + case MATCH_FCVT_L_D: + case MATCH_FCVT_L_D | MASK_RM: + TRACE_INSN (cpu, "fcvt.l.d %s, %s, rm=%d;", rd_name, rs1_name, rm); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + convert_double_to_long (cpu, rd, rs1, SIGNED, rm); + break; + case MATCH_FCVT_LU_D: + case MATCH_FCVT_LU_D | MASK_RM: + TRACE_INSN (cpu, "fcvt.lu.d %s, %s, rm=%d;", rd_name, rs1_name, rm); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + convert_double_to_long (cpu, rd, rs1, UNSIGNED, rm); + break; + case MATCH_FCVT_D_L: + case MATCH_FCVT_D_L | MASK_RM: + TRACE_INSN (cpu, "fcvt.d.l %s, %s, rm=%d;", rd_name, rs1_name, rm); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + convert_long_to_double (cpu, rd, rs1, SIGNED, rm); + break; + case MATCH_FCVT_D_LU: + case MATCH_FCVT_D_LU | MASK_RM: + TRACE_INSN (cpu, "fcvt.d.lu %s, %s, rm=%d;", rd_name, rs1_name, rm); + RISCV_ASSERT_RV64 (cpu, "insn: %s", op->name); + convert_long_to_double (cpu, rd, rs1, UNSIGNED, rm); + break; + case MATCH_FCVT_S_D: + case MATCH_FCVT_S_D | MASK_RM: + double_to_float (cpu, rd, rs1, rm); + break; + case MATCH_FCVT_D_S: + { + float f; + double d; + uint64_t rd_bits; + uint32_t rs1_bits; + TRACE_INSN (cpu, "fcvt.d.s %s, %s;", frd_name, frs1_name); + rs1_bits = (uint32_t) riscv_cpu->fpregs[rs1]; + memcpy (&f, &rs1_bits, sizeof (f)); + d = (double) f; + memcpy (&rd_bits, &d, sizeof (d)); + store_fp (cpu, rd, rd_bits); + break; + } default: TRACE_INSN (cpu, "UNHANDLED INSN: %s", op->name); sim_engine_halt (sd, cpu, NULL, riscv_cpu->pc, sim_signalled, SIM_SIGILL); diff --git a/sim/testsuite/riscv/d-conversion.s b/sim/testsuite/riscv/d-conversion.s new file mode 100755 index 00000000000..e2ca0a3e1c7 --- /dev/null +++ b/sim/testsuite/riscv/d-conversion.s @@ -0,0 +1,111 @@ +# Double precision conversion tests. +# mach: riscv32 riscv64 +# sim(riscv64): --model RV64ID +# ld(riscv64): -m elf64lriscv +# as(riscv64): -march=rv64id + +.include "testutils.inc" + + .section .rodata + .align 3 + +_arg1: + .double 123.49 + .word 123 + .word 0 + .double -3e9 + .double 2147483648.5 + .dword 2147483647 + .float -12.5 + .float .0 + .double -12.5 + +_result: + .word 123 + .word 0 + .double 123.0 + .dword -3000000000 + .dword 2147483648 + .double 2147483647 + .double -12.5 + .float -12.5 + + start + .option push + .option norelax + la a0,_arg1 + la a1,_result + li a2,1 + .option pop + + # Test fcvt.w.d instruction. + fld fa0,0(a0) + lw a3,0(a1) + fcvt.w.d a5,fa0,rne + bne a3,a5,test_fail + + # Test fcvt.wu.d instruction. + fld fa0,0(a0) + lw a3,0(a1) + fcvt.wu.d a5,fa0,rne + bne a3,a5,test_fail + + # Test fcvt.d.w instruction. + lw a3,8(a0) + fld fa0,8(a1) + fcvt.d.w fa1,a3 + feq.d a4,fa0,fa1 + bne a4,a2,test_fail + + # Test fcvt.d.wu instruction. + lw a3,8(a0) + fld fa0,8(a1) + fcvt.d.wu fa1,a3 + feq.d a4,fa0,fa1 + bne a4,a2,test_fail + + # Test fcvt.l.d instruction. + fld fa0,16(a0) + ld a3,16(a1) + fcvt.l.d a5,fa0,rne + bne a5,a3,test_fail + + # Test fcvt.lu.d instruction. + fld fa0,24(a0) + ld a3,24(a1) + fcvt.lu.d a5,fa0,rne + bne a5,a3,test_fail + + # Test fcvt.d.l instruction. + ld a3,32(a0) + fld fa0,32(a1) + fcvt.d.l fa1,a3,rne + feq.d a4,fa0,fa1 + bne a4,a2,test_fail + + # Test fcvt.d.lu instruction. + ld a3,32(a0) + fld fa0,32(a1) + fcvt.d.lu fa1,a3,rne + feq.d a4,fa0,fa1 + bne a4,a2,test_fail + + # Test fcvt.d.s instruction. + flw fa0,40(a0) + fld fa1,40(a1) + fcvt.d.s fa2,fa0 + feq.d a4,fa2,fa1 + bne a4,a2,test_fail + + # Test fcvt.s.d instruction. + fld fa0,48(a0) + flw fa1,48(a1) + fcvt.s.d fa2,fa0 + feq.s a4,fa2,fa1 + bne a4,a2,test_fail + +test_pass: + pass + +test_fail: + fail