diff options
author | Alec Roelke <ar4jc@virginia.edu> | 2016-11-30 17:12:56 -0500 |
---|---|---|
committer | Alec Roelke <ar4jc@virginia.edu> | 2016-11-30 17:12:56 -0500 |
commit | 33683bd087c2009db588844e8fa89b454a5c3d77 (patch) | |
tree | e276700fc7838cb322d830abebffcc6215d0cee0 /tests/test-progs | |
parent | ee0c261e10c17cb1ce0a1511bb1040318e6d17f9 (diff) | |
download | gem5-33683bd087c2009db588844e8fa89b454a5c3d77.tar.xz |
riscv: [Patch 8/5] Added some regression tests to RISC-V
This patch is the eighth patch in a series adding RISC-V to gem5, and
third of the bonus patches to the original series of five. It adds some
regression tests to RISC-V.
Regression tests included:
- se/00.hello
- se/02.insttest (split into several binaries which are not included due
to large size)
The tests added to 00.insttest will need to be build manually; to
facilitate this, a Makefile is included. The required toolchain and
compiler (riscv64-unknown-elf-gcc) can be built from the riscv-tools
GitHub repository at https://github.com/riscv/riscv-tools.
Note that because EBREAK only makes sense when gdb is running or while in
FS mode, it is not included in the linux-rv64i insttest. ERET is not
included because it does not make sense in SE mode and, in fact, causes
a panic by design.
Note also that not every system call is tested in linux-rv64i; of the ones
defined in linux/process.hh, some have been given numbers but not
definitions for the toolchain, or are merely stubs that always return 0. Of
the ones that do work properly, only a subset are tested due to similar
functionality.
Signed-off by: Alec Roelke
Signed-off by: Jason Lowe-Power <jason@lowepower.com>
Diffstat (limited to 'tests/test-progs')
-rwxr-xr-x | tests/test-progs/hello/bin/riscv/linux/hello | bin | 0 -> 180264 bytes | |||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/Makefile | 51 | ||||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/insttest.h | 79 | ||||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/rv64a.cpp | 192 | ||||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/rv64a.h | 299 | ||||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/rv64d.cpp | 708 | ||||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/rv64d.h | 323 | ||||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/rv64f.cpp | 694 | ||||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/rv64f.h | 357 | ||||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/rv64i.cpp | 432 | ||||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/rv64i.h | 440 | ||||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/rv64m.cpp | 143 | ||||
-rw-r--r-- | tests/test-progs/insttest/src/riscv/rv64m.h | 144 |
13 files changed, 3862 insertions, 0 deletions
diff --git a/tests/test-progs/hello/bin/riscv/linux/hello b/tests/test-progs/hello/bin/riscv/linux/hello Binary files differnew file mode 100755 index 000000000..7f1ca493b --- /dev/null +++ b/tests/test-progs/hello/bin/riscv/linux/hello diff --git a/tests/test-progs/insttest/src/riscv/Makefile b/tests/test-progs/insttest/src/riscv/Makefile new file mode 100644 index 000000000..5aa8a7a3b --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/Makefile @@ -0,0 +1,51 @@ +# Copyright (c) 2016 The University of Virginia +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Alec Roelke + +CXX=riscv64-unknown-elf-g++ +CFLAGS=--std=c++11 -O3 -static + +TARGETS=rv64i rv64m rv64a rv64f rv64d +PREFIX=../../bin/riscv/linux +BIN=insttest + +all: $(TARGETS) + +$(TARGETS): + -mkdir -p $(PREFIX)-$@ + $(CXX) $< $(CFLAGS) -o $(PREFIX)-$@/$(BIN) + +rv64i: rv64i.cpp +rv64m: rv64m.cpp +rv64a: rv64a.cpp +rv64f: rv64f.cpp +rv64d: rv64d.cpp + +clean: + -rm $(PREFIX)-*/$(BIN) + +.PHONY: all clean diff --git a/tests/test-progs/insttest/src/riscv/insttest.h b/tests/test-progs/insttest/src/riscv/insttest.h new file mode 100644 index 000000000..59b69869c --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/insttest.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#pragma once + +#include <cmath> +#include <cstdlib> +#include <functional> +#include <iostream> +#include <string> + +#define IOP(inst, rd, rs1, imm) \ + asm volatile(inst " %0,%1,%2" : "=r" (rd) : "r" (rs1), "i" (imm)) + +#define ROP(inst, rd, rs1, rs2) \ + asm volatile(inst " %0,%1,%2" : "=r" (rd) : "r" (rs1), "r" (rs2)) + +#define FROP(inst, fd, fs1, fs2) \ + asm volatile(inst " %0,%1,%2" : "=f" (fd) : "f" (fs1), "f" (fs2)) + +#define FR4OP(inst, fd, fs1, fs2, fs3) \ + asm volatile(inst " %0,%1,%2,%3" \ + : "=f" (fd) \ + : "f" (fs1), "f" (fs2), "f" (fs3)) + +template<typename A, typename B> std::ostream& +operator<<(std::ostream& os, const std::pair<A, B>& p) +{ + return os << '(' << p.first << ", " << p.second << ')'; +} + +namespace insttest +{ + +template<typename T> void +expect(const T& expected, std::function<T()> func, + const std::string& test) +{ + using namespace std; + + T result = func(); + cout << test << ": "; + if (result == expected) { + cout << "PASS" << endl; + } else { + cout << "\033[1;31mFAIL\033[0m (expected " << expected << "; found " << + result << ")" << endl; + exit(1); + } +} + +} // namespace insttest diff --git a/tests/test-progs/insttest/src/riscv/rv64a.cpp b/tests/test-progs/insttest/src/riscv/rv64a.cpp new file mode 100644 index 000000000..55150fbc3 --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/rv64a.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#include <cstdint> +#include <limits> + +#include "insttest.h" +#include "rv64a.h" + +int main() +{ + using namespace std; + using namespace insttest; + + // Memory (LR.W, SC.W) + expect<pair<int64_t, uint64_t>>({-1, 0}, []{ + int32_t mem = -1; + int64_t rs2 = 256; + int64_t rd = A::lr_w(mem); + pair<int64_t, uint64_t> result = A::sc_w(rs2, mem); + return pair<int64_t, uint64_t>(rd, result.second); + }, "lr.w/sc.w"); + expect<pair<bool, int64_t>>({true, 200}, []{ + int32_t mem = 200; + pair<int64_t, uint64_t> result = A::sc_w(50, mem); + return pair<bool, int64_t>(result.second == 1, mem); + }, "sc.w, no preceding lr.d"); + + // AMOSWAP.W + expect<pair<int64_t, int64_t>>({65535, 255}, + []{return A::amoswap_w(255, 65535);}, "amoswap.w"); + expect<pair<int64_t, int64_t>>({0xFFFFFFFF, -1}, + []{return A::amoswap_w(0xFFFFFFFF, 0xFFFFFFFF);}, + "amoswap.w, sign extend"); + expect<pair<int64_t, int64_t>>({0x0000000180000000LL, -1}, + []{return A::amoswap_w(0x00000001FFFFFFFFLL, + 0x7FFFFFFF80000000LL);}, + "amoswap.w, truncate"); + + // AMOADD.W + expect<pair<int64_t, int64_t>>({256, 255}, + []{return A::amoadd_w(255, 1);}, "amoadd.w"); + expect<pair<int64_t, int64_t>>({0, -1}, + []{return A::amoadd_w(0xFFFFFFFF, 1);}, + "amoadd.w, truncate/overflow"); + expect<pair<int64_t, int64_t>>({0xFFFFFFFF, 0x7FFFFFFF}, + []{return A::amoadd_w(0x7FFFFFFF, 0x80000000);}, + "amoadd.w, sign extend"); + + // AMOXOR.W + expect<pair<uint64_t, uint64_t>>({0xFFFFFFFFAAAAAAAALL, -1}, + []{return A::amoxor_w(-1, 0x5555555555555555LL);}, + "amoxor.w, truncate"); + expect<pair<uint64_t, uint64_t>>({0x80000000, -1}, + []{return A::amoxor_w(0xFFFFFFFF, 0x7FFFFFFF);}, + "amoxor.w, sign extend"); + + // AMOAND.W + expect<pair<uint64_t, uint64_t>>({0xFFFFFFFF00000000LL, -1}, + []{return A::amoand_w(-1, 0);}, "amoand.w, truncate"); + expect<pair<uint64_t, uint64_t>>({0x0000000080000000LL, -1}, + []{return A::amoand_w(0xFFFFFFFF,numeric_limits<int32_t>::min());}, + "amoand.w, sign extend"); + + // AMOOR.W + expect<pair<uint64_t, uint64_t>>({0x00000000FFFFFFFFLL, 0}, + []{return A::amoor_w(0, -1);}, "amoor.w, truncate"); + expect<pair<uint64_t, uint64_t>>({0x0000000080000000LL, 0}, + []{return A::amoor_w(0, numeric_limits<int32_t>::min());}, + "amoor.w, sign extend"); + + // AMOMIN.W + expect<pair<int64_t, int64_t>>({0x7FFFFFFF00000001LL, 1}, + []{return A::amomin_w(0x7FFFFFFF00000001LL, 0xFFFFFFFF000000FF);}, + "amomin.w, truncate"); + expect<pair<int64_t, int64_t>>({0x00000000FFFFFFFELL, -1}, + []{return A::amomin_w(0xFFFFFFFF, -2);}, "amomin.w, sign extend"); + + // AMOMAX.W + expect<pair<int64_t, int64_t>>({0x70000000000000FFLL, 1}, + []{return A::amomax_w(0x7000000000000001LL,0x7FFFFFFF000000FFLL);}, + "amomax.w, truncate"); + expect<pair<int64_t, int64_t>>({-1, numeric_limits<int32_t>::min()}, + []{return A::amomax_w(numeric_limits<int32_t>::min(), -1);}, + "amomax.w, sign extend"); + + // AMOMINU.W + expect<pair<uint64_t, uint64_t>>({0x0FFFFFFF000000FFLL, -1}, + []{return A::amominu_w(0x0FFFFFFFFFFFFFFFLL, 0xFFFFFFFF000000FF);}, + "amominu.w, truncate"); + expect<pair<uint64_t, uint64_t>>({0x0000000080000000LL, -1}, + []{return A::amominu_w(0x00000000FFFFFFFFLL, 0x80000000);}, + "amominu.w, sign extend"); + + // AMOMAXU.W + expect<pair<uint64_t, uint64_t>>({-1, 0}, + []{return A::amomaxu_w(0xFFFFFFFF00000000LL, + 0x00000000FFFFFFFFLL);}, + "amomaxu.w, truncate"); + expect<pair<uint64_t, uint64_t>>( + {0xFFFFFFFF, numeric_limits<int32_t>::min()}, + []{return A::amomaxu_w(0x80000000, 0xFFFFFFFF);}, + "amomaxu.w, sign extend"); + + // Memory (LR.D, SC.D) + expect<pair<int64_t, uint64_t>>({-1, 0}, []{ + int64_t mem = -1; + int64_t rs2 = 256; + int64_t rd = A::lr_d(mem); + pair<int64_t, uint64_t> result = A::sc_d(rs2, mem); + return pair<int64_t, uint64_t>(rd, result.second); + }, "lr.d/sc.d"); + expect<pair<bool, int64_t>>({true, 200}, []{ + int64_t mem = 200; + pair<int64_t, uint64_t> result = A::sc_d(50, mem); + return pair<bool, int64_t>(result.second == 1, mem); + }, "sc.d, no preceding lr.d"); + + // AMOSWAP.D + expect<pair<int64_t, int64_t>>({1, -1}, []{return A::amoswap_d(-1, 1);}, + "amoswap.d"); + + // AMOADD.D + expect<pair<int64_t, int64_t>>({0x7000000000000000LL,0x0FFFFFFFFFFFFFFFLL}, + []{return A::amoadd_d(0x0FFFFFFFFFFFFFFFLL,0x6000000000000001LL);}, + "amoadd.d"); + expect<pair<int64_t, int64_t>>({0, 0x7FFFFFFFFFFFFFFFLL}, + []{return A::amoadd_d(0x7FFFFFFFFFFFFFFFLL,0x8000000000000001LL);}, + "amoadd.d, overflow"); + + // AMOXOR.D + expect<pair<int64_t, int64_t>>({-1, 0xAAAAAAAAAAAAAAAALL}, + []{return A::amoxor_d(0xAAAAAAAAAAAAAAAALL,0x5555555555555555LL);}, + "amoxor.d (1)"); + expect<pair<int64_t, int64_t>>({0, 0xAAAAAAAAAAAAAAAALL}, + []{return A::amoxor_d(0xAAAAAAAAAAAAAAAALL,0xAAAAAAAAAAAAAAAALL);}, + "amoxor.d (0)"); + + // AMOAND.D + expect<pair<int64_t, int64_t>>({0xAAAAAAAAAAAAAAAALL, -1}, + []{return A::amoand_d(-1, 0xAAAAAAAAAAAAAAAALL);}, "amoand.d"); + + // AMOOR.D + expect<pair<int64_t, int64_t>>({-1, 0xAAAAAAAAAAAAAAAALL}, + []{return A::amoor_d(0xAAAAAAAAAAAAAAAALL, 0x5555555555555555LL);}, + "amoor.d"); + + // AMOMIN.D + expect<pair<int64_t, int64_t>>({-1, -1}, + []{return A::amomin_d(-1, 0);}, "amomin.d"); + + // AMOMAX.D + expect<pair<int64_t, int64_t>>({0, -1}, []{return A::amomax_d(-1, 0);}, + "amomax.d"); + + // AMOMINU.D + expect<pair<uint64_t, uint64_t>>({0, -1}, + []{return A::amominu_d(-1, 0);}, "amominu.d"); + + // AMOMAXU.D + expect<pair<uint64_t, uint64_t>>({-1, -1}, []{return A::amomaxu_d(-1, 0);}, + "amomaxu.d"); + + return 0; +} diff --git a/tests/test-progs/insttest/src/riscv/rv64a.h b/tests/test-progs/insttest/src/riscv/rv64a.h new file mode 100644 index 000000000..cfd1fd846 --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/rv64a.h @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#pragma once + +#include <cstdint> +#include <tuple> + +#include "insttest.h" + +namespace A +{ + +inline int64_t +lr_w(int32_t& mem) +{ + int64_t r = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("lr.w %0,(%1)" : "=r" (r) : "r" (addr) : "memory"); + return r; +} + +inline std::pair<int64_t, uint64_t> +sc_w(int64_t rs2, int32_t& mem) +{ + uint64_t addr = (uint64_t)&mem; + uint64_t rd = -1; + asm volatile("sc.w %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<int64_t, int64_t> +amoswap_w(int64_t mem, int64_t rs2) +{ + int64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amoswap.w %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<int64_t, int64_t> +amoadd_w(int64_t mem, int64_t rs2) +{ + int64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amoadd.w %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<uint64_t, uint64_t> +amoxor_w(uint64_t mem, uint64_t rs2) +{ + uint64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amoxor.w %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<uint64_t, uint64_t> +amoand_w(uint64_t mem, uint64_t rs2) +{ + uint64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amoand.w %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<uint64_t, uint64_t> +amoor_w(uint64_t mem, uint64_t rs2) +{ + uint64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amoor.w %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<int64_t, int64_t> +amomin_w(int64_t mem, int64_t rs2) +{ + int64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amomin.w %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<int64_t, int64_t> +amomax_w(int64_t mem, int64_t rs2) +{ + int64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amomax.w %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<uint64_t, uint64_t> +amominu_w(uint64_t mem, uint64_t rs2) +{ + uint64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amominu.w %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<uint64_t, uint64_t> +amomaxu_w(uint64_t mem, uint64_t rs2) +{ + uint64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amomaxu.w %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline int64_t +lr_d(int64_t& mem) +{ + int64_t r = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("lr.d %0,(%1)" : "=r" (r) : "r" (addr) : "memory"); + return r; +} + +inline std::pair<int64_t, uint64_t> +sc_d(int64_t rs2, int64_t& mem) +{ + uint64_t addr = (uint64_t)&mem; + uint64_t rd = -1; + asm volatile("sc.d %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<int64_t, int64_t> +amoswap_d(int64_t mem, int64_t rs2) +{ + int64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amoswap.d %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<int64_t, int64_t> +amoadd_d(int64_t mem, int64_t rs2) +{ + int64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amoadd.d %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<uint64_t, uint64_t> +amoxor_d(uint64_t mem, uint64_t rs2) +{ + uint64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amoxor.d %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<uint64_t, uint64_t> +amoand_d(uint64_t mem, uint64_t rs2) +{ + uint64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amoand.d %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<uint64_t, uint64_t> +amoor_d(uint64_t mem, uint64_t rs2) +{ + uint64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amoor.d %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<int64_t, int64_t> +amomin_d(int64_t mem, int64_t rs2) +{ + int64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amomin.d %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<int64_t, int64_t> +amomax_d(int64_t mem, int64_t rs2) +{ + int64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amomax.d %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<uint64_t, uint64_t> +amominu_d(uint64_t mem, uint64_t rs2) +{ + uint64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amominu.d %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +inline std::pair<uint64_t, uint64_t> +amomaxu_d(uint64_t mem, uint64_t rs2) +{ + uint64_t rd = 0; + uint64_t addr = (uint64_t)&mem; + asm volatile("amomaxu.d %0,%2,(%1)" + : "=r" (rd) + : "r" (addr), "r" (rs2) + : "memory"); + return {mem, rd}; +} + +} // namespace A diff --git a/tests/test-progs/insttest/src/riscv/rv64d.cpp b/tests/test-progs/insttest/src/riscv/rv64d.cpp new file mode 100644 index 000000000..adb62d2f5 --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/rv64d.cpp @@ -0,0 +1,708 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#include <cstdint> +#include <limits> + +#include "insttest.h" +#include "rv64d.h" +#include "rv64f.h" + +int main() +{ + using namespace std; + using namespace insttest; + + // Memory (FLD, FSD) + expect<double>(3.1415926, []{return D::load(3.1415926);}, "fld"); + expect<double>(1.61803398875, []{return D::store(1.61803398875);}, "fsd"); + + // FMADD.D + expect<double>(D::number(0x4019FD5AED13B1CEULL), + []{return D::fmadd_d(3.1415926, 1.61803398875,1.41421356237);}, + "fmadd.d"); + expect<bool>(true, []{ + double fd = D::fmadd_d(numeric_limits<double>::quiet_NaN(), 3.14, + 1.816); + return D::isquietnan(fd); + }, "fmadd.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fmadd_d(3.14, + numeric_limits<double>::signaling_NaN(), 1.816); + return D::isquietnan(fd); + }, "fmadd.d, signaling NaN"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fmadd_d(3.14, numeric_limits<double>::infinity(),1.414);}, + "fmadd.d, infinity"); + expect<double>(-numeric_limits<double>::infinity(), + []{return D::fmadd_d(3.14,-numeric_limits<double>::infinity(),1.414);}, + "fmadd.d, -infinity"); + + // FMSUB.D + expect<double>(D::number(0x400d5A1773A85E43ULL), + []{return D::fmsub_d(3.1415926, 1.61803398875, 1.41421356237);}, + "fmsub.d"); + expect<bool>(true, []{ + double fd = D::fmsub_d(3.14, numeric_limits<double>::quiet_NaN(), + 1.414); + return D::isquietnan(fd); + }, "fmsub.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fmsub_d(3.14, 1.816, + numeric_limits<double>::signaling_NaN()); + return D::isquietnan(fd); + }, "fmsub.d, signaling NaN"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fmsub_d(numeric_limits<double>::infinity(), 1.816, + 1.414);}, + "fmsub.d, infinity"); + expect<double>(-numeric_limits<double>::infinity(), + []{return D::fmsub_d(3.14, -numeric_limits<double>::infinity(), + 1.414);}, + "fmsub.d, -infinity"); + expect<double>(-numeric_limits<double>::infinity(), + []{return D::fmsub_d(3.14, 1.816, + numeric_limits<double>::infinity());}, + "fmsub.d, subtract infinity"); + + // FNMSUB.D + expect<double>(D::number(0xC00D5A1773A85E43ULL), + []{return D::fnmsub_d(3.1415926, 1.61803398875, 1.41421356237);}, + "fnmsub.d"); + expect<bool>(true, []{ + double fd = D::fnmsub_d(3.14, 1.816, + numeric_limits<double>::quiet_NaN()); + return D::isquietnan(fd); + }, "fnmsub.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fnmsub_d(numeric_limits<double>::signaling_NaN(), + 1.816, 1.414); + return D::isquietnan(fd); + }, "fnmsub.d, signaling NaN"); + expect<double>(-numeric_limits<double>::infinity(), + []{return D::fnmsub_d(numeric_limits<double>::infinity(), 1.816, + 1.414);}, + "fnmsub.d, infinity"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fnmsub_d(3.14, -numeric_limits<double>::infinity(), + 1.414);}, + "fnmsub.d, -infinity"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fnmsub_d(3.14, 1.816, + numeric_limits<double>::infinity());}, + "fnmsub.d, subtract infinity"); + + // FNMADD.D + expect<double>(D::number(0xC019FD5AED13B1CEULL), + []{return D::fnmadd_d(3.1415926, 1.61803398875, 1.41421356237);}, + "fnmadd.d"); + expect<bool>(true, []{ + double fd = D::fnmadd_d(numeric_limits<double>::quiet_NaN(), 3.14, + 1.816); + return D::isquietnan(fd); + }, "fnmadd.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fnmadd_d(3.14, + numeric_limits<double>::signaling_NaN(), 1.816); + return D::isquietnan(fd); + }, "fnmadd.d, signaling NaN"); + expect<double>(-numeric_limits<double>::infinity(), + []{return D::fnmadd_d(3.14, numeric_limits<double>::infinity(), + 1.414);}, + "fnmadd.d, infinity"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fnmadd_d(3.14, -numeric_limits<double>::infinity(), + 1.414);}, + "fnmadd.d, -infinity"); + + // FADD.D + expect<double>(D::number(0x4012392540292D7CULL), + []{return D::fadd_d(3.1415926, 1.41421356237);}, "fadd.d"); + expect<bool>(true, []{ + double fd = D::fadd_d(numeric_limits<double>::quiet_NaN(), 1.414); + return D::isquietnan(fd); + }, "fadd.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fadd_d(3.14, + numeric_limits<double>::signaling_NaN()); + return D::isquietnan(fd); + }, "fadd.d, signaling NaN"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fadd_d(3.14, numeric_limits<double>::infinity());}, + "fadd.d, infinity"); + expect<double>(-numeric_limits<double>::infinity(), + []{return D::fadd_d(-numeric_limits<double>::infinity(), 1.816);}, + "fadd.d, -infinity"); + + // FSUB.D + expect<double>(D::number(0xBFFBA35833AB7AAEULL), + []{return D::fsub_d(1.4142135623, 3.1415926);}, "fsub.d"); + expect<bool>(true, []{ + double fd = D::fsub_d(numeric_limits<double>::quiet_NaN(), 1.414); + return D::isquietnan(fd); + }, "fsub.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fsub_d(3.14, + numeric_limits<double>::signaling_NaN()); + return D::isquietnan(fd); + }, "fsub.d, signaling NaN"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fsub_d(numeric_limits<double>::infinity(), 3.14);}, + "fsub.d, infinity"); + expect<double>(-numeric_limits<double>::infinity(), + []{return D::fsub_d(-numeric_limits<double>::infinity(), 3.14);}, + "fsub.d, -infinity"); + expect<double>(-numeric_limits<double>::infinity(), + []{return D::fsub_d(1.414, numeric_limits<double>::infinity());}, + "fsub.d, subtract infinity"); + + // FMUL.D + expect<double>(D::number(0x40024E53B708ED9AULL), + []{return D::fmul_d(1.61803398875, 1.4142135623);}, "fmul.d"); + expect<bool>(true, []{ + double fd = D::fmul_d(numeric_limits<double>::quiet_NaN(), 1.414); + return D::isquietnan(fd); + }, "fmul.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fmul_d(1.816, + numeric_limits<double>::signaling_NaN()); + return D::isquietnan(fd); + }, "fmul.d, signaling NaN"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fmul_d(numeric_limits<double>::infinity(), 2.718);}, + "fmul.d, infinity"); + expect<double>(-numeric_limits<double>::infinity(), + []{return D::fmul_d(2.5966, -numeric_limits<double>::infinity());}, + "fmul.d, -infinity"); + expect<bool>(true, []{ + double fd = D::fmul_d(0.0, numeric_limits<double>::infinity()); + return D::isquietnan(fd); + }, "fmul.d, 0*infinity"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fmul_d(numeric_limits<double>::max(), 2.0);}, + "fmul.d, overflow"); + expect<double>(0.0, + []{return D::fmul_d(numeric_limits<double>::min(), + numeric_limits<double>::min());}, + "fmul.d, underflow"); + + // FDIV.D + expect<double>(2.5, []{return D::fdiv_d(10.0, 4.0);}, "fdiv.d"); + expect<bool>(true, []{ + double fd = D::fdiv_d(numeric_limits<double>::quiet_NaN(), 4.0); + return D::isquietnan(fd); + }, "fdiv.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fdiv_d(10.0, + numeric_limits<double>::signaling_NaN()); + return D::isquietnan(fd); + }, "fdiv.d, signaling NaN"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fdiv_d(10.0, 0.0);}, "fdiv.d/0"); + expect<double>(0.0, + []{return D::fdiv_d(10.0, numeric_limits<double>::infinity());}, + "fdiv.d/infinity"); + expect<bool>(true, []{ + double fd = D::fdiv_d(numeric_limits<double>::infinity(), + numeric_limits<double>::infinity()); + return D::isquietnan(fd); + }, "fdiv.d, infinity/infinity"); + expect<bool>(true, []{ + double fd = D::fdiv_d(0.0, 0.0); + return D::isquietnan(fd); + }, "fdiv.d, 0/0"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fdiv_d(numeric_limits<double>::infinity(), 0.0);}, + "fdiv.d, infinity/0"); + expect<double>(0.0, + []{return D::fdiv_d(0.0, numeric_limits<double>::infinity());}, + "fdiv.d, 0/infinity"); + expect<double>(0.0, + []{return D::fdiv_d(numeric_limits<double>::min(), + numeric_limits<double>::max());}, + "fdiv.d, underflow"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fdiv_d(numeric_limits<double>::max(), + numeric_limits<double>::min());}, + "fdiv.d, overflow"); + + // FSQRT.D + expect<double>(1e154, []{return D::fsqrt_d(1e308);}, "fsqrt.d"); + expect<bool>(true, []{ + double fd = D::fsqrt_d(-1.0); + return D::isquietnan(fd); + }, "fsqrt.d, NaN"); + expect<bool>(true, []{ + double fd = D::fsqrt_d(numeric_limits<double>::quiet_NaN()); + return D::isquietnan(fd); + }, "fsqrt.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fsqrt_d(numeric_limits<double>::signaling_NaN()); + return D::isquietnan(fd); + }, "fsqrt.d, signaling NaN"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fsqrt_d(numeric_limits<double>::infinity());}, + "fsqrt.d, infinity"); + + // FSGNJ.D + expect<double>(1.0, []{return D::fsgnj_d(1.0, 25.0);}, "fsgnj.d, ++"); + expect<double>(-1.0, []{return D::fsgnj_d(1.0, -25.0);}, "fsgnj.d, +-"); + expect<double>(1.0, []{return D::fsgnj_d(-1.0, 25.0);}, "fsgnj.d, -+"); + expect<double>(-1.0, []{return D::fsgnj_d(-1.0, -25.0);}, "fsgnj.d, --"); + expect<bool>(true, []{ + double fd = D::fsgnj_d(numeric_limits<double>::quiet_NaN(), -4.0); + return D::isquietnan(fd); + }, "fsgnj.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fsgnj_d(numeric_limits<double>::signaling_NaN(), + -4.0); + return D::issignalingnan(fd); + }, "fsgnj.d, signaling NaN"); + expect<double>(4.0, + []{return D::fsgnj_d(4.0, numeric_limits<double>::quiet_NaN());}, + "fsgnj.d, inject NaN"); + expect<double>(-4.0, + []{return D::fsgnj_d(4.0, -numeric_limits<double>::quiet_NaN());}, + "fsgnj.d, inject -NaN"); + + // FSGNJN.D + expect<double>(-1.0, []{return D::fsgnjn_d(1.0, 25.0);}, "fsgnjn.d, ++"); + expect<double>(1.0, []{return D::fsgnjn_d(1.0, -25.0);}, "fsgnjn.d, +-"); + expect<double>(-1.0, []{return D::fsgnjn_d(-1.0, 25.0);}, "fsgnjn.d, -+"); + expect<double>(1.0, []{return D::fsgnjn_d(-1.0, -25.0);}, "fsgnjn.d, --"); + expect<bool>(true, []{ + double fd = D::fsgnjn_d(numeric_limits<double>::quiet_NaN(), -4.0); + return D::isquietnan(fd); + }, "fsgnjn.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fsgnjn_d(numeric_limits<double>::signaling_NaN(), + -4.0); + return D::issignalingnan(fd); + }, "fsgnjn.d, signaling NaN"); + expect<double>(-4.0, + []{return D::fsgnjn_d(4.0, numeric_limits<double>::quiet_NaN());}, + "fsgnjn.d, inject NaN"); + expect<double>(4.0, + []{return D::fsgnjn_d(4.0, -numeric_limits<double>::quiet_NaN());}, + "fsgnjn.d, inject NaN"); + + // FSGNJX.D + expect<double>(1.0, []{return D::fsgnjx_d(1.0, 25.0);}, "fsgnjx.d, ++"); + expect<double>(-1.0, []{return D::fsgnjx_d(1.0, -25.0);}, "fsgnjx.d, +-"); + expect<double>(-1.0, []{return D::fsgnjx_d(-1.0, 25.0);}, "fsgnjx.d, -+"); + expect<double>(1.0, []{return D::fsgnjx_d(-1.0, -25.0);}, "fsgnjx.d, --"); + expect<bool>(true, []{ + double fd = D::fsgnjx_d(numeric_limits<double>::quiet_NaN(), -4.0); + return D::isquietnan(fd); + }, "fsgnjx.d, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fsgnjx_d(numeric_limits<double>::signaling_NaN(), + -4.0); + return D::issignalingnan(fd); + }, "fsgnjx.d, signaling NaN"); + expect<double>(4.0, + []{return D::fsgnjx_d(4.0, numeric_limits<double>::quiet_NaN());}, + "fsgnjx.d, inject NaN"); + expect<double>(-4.0, + []{return D::fsgnjx_d(4.0, -numeric_limits<double>::quiet_NaN());}, + "fsgnjx.d, inject NaN"); + + // FMIN.D + expect<double>(2.718, []{return D::fmin_d(3.14, 2.718);}, "fmin.d"); + expect<double>(-numeric_limits<double>::infinity(), + []{return D::fmin_d(-numeric_limits<double>::infinity(), + numeric_limits<double>::min());}, + "fmin.d, -infinity"); + expect<double>(numeric_limits<double>::max(), + []{return D::fmin_d(numeric_limits<double>::infinity(), + numeric_limits<double>::max());}, + "fmin.d, infinity"); + expect<double>(-1.414, + []{return D::fmin_d(numeric_limits<double>::quiet_NaN(), -1.414);}, + "fmin.d, quiet NaN first"); + expect<double>(2.718, + []{return D::fmin_d(2.718, numeric_limits<double>::quiet_NaN());}, + "fmin.d, quiet NaN second"); + expect<bool>(true, []{ + double fd = D::fmin_d(numeric_limits<double>::quiet_NaN(), + numeric_limits<double>::quiet_NaN()); + return D::isquietnan(fd); + }, "fmin.d, quiet NaN both"); + expect<double>(3.14, + []{return D::fmin_d(numeric_limits<double>::signaling_NaN(), + 3.14);}, + "fmin.d, signaling NaN first"); + expect<double>(1.816, + []{return D::fmin_d(1.816, + numeric_limits<double>::signaling_NaN());}, + "fmin.d, signaling NaN second"); + expect<bool>(true, []{ + double fd = D::fmin_d(numeric_limits<double>::signaling_NaN(), + numeric_limits<double>::signaling_NaN()); + return D::issignalingnan(fd); + }, "fmin.d, signaling NaN both"); + + // FMAX.D + expect<double>(3.14, []{return D::fmax_d(3.14, 2.718);}, "fmax.d"); + expect<double>(numeric_limits<double>::min(), + []{return D::fmax_d(-numeric_limits<double>::infinity(), + numeric_limits<double>::min());}, + "fmax.d, -infinity"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fmax_d(numeric_limits<double>::infinity(), + numeric_limits<double>::max());}, + "fmax.d, infinity"); + expect<double>(-1.414, + []{return D::fmax_d(numeric_limits<double>::quiet_NaN(), -1.414);}, + "fmax.d, quiet NaN first"); + expect<double>(2.718, + []{return D::fmax_d(2.718, numeric_limits<double>::quiet_NaN());}, + "fmax.d, quiet NaN second"); + expect<bool>(true, []{ + double fd = D::fmax_d(numeric_limits<double>::quiet_NaN(), + numeric_limits<double>::quiet_NaN()); + return D::isquietnan(fd); + }, "fmax.d, quiet NaN both"); + expect<double>(3.14, + []{return D::fmax_d(numeric_limits<double>::signaling_NaN(), + 3.14);}, + "fmax.d, signaling NaN first"); + expect<double>(1.816, + []{return D::fmax_d(1.816, + numeric_limits<double>::signaling_NaN());}, + "fmax.d, signaling NaN second"); + expect<bool>(true, []{ + double fd = D::fmax_d(numeric_limits<double>::signaling_NaN(), + numeric_limits<double>::signaling_NaN()); + return D::issignalingnan(fd); + }, "fmax.d, signaling NaN both"); + + // FCVT.S.D + expect<float>(4.0, []{return D::fcvt_s_d(4.0);}, "fcvt.s.d"); + expect<bool>(true, []{ + float fd = D::fcvt_s_d(numeric_limits<double>::quiet_NaN()); + return F::isquietnan(fd); + }, "fcvt.s.d, quiet NaN"); + expect<bool>(true, []{ + float fd = D::fcvt_s_d(numeric_limits<double>::signaling_NaN()); + return F::isquietnan(fd); + }, "fcvt.s.d, signaling NaN"); + expect<float>(numeric_limits<float>::infinity(), + []{return D::fcvt_s_d(numeric_limits<double>::infinity());}, + "fcvt.s.d, infinity"); + expect<float>(numeric_limits<float>::infinity(), + []{return D::fcvt_s_d(numeric_limits<double>::max());}, + "fcvt.s.d, overflow"); + expect<float>(0.0, []{return D::fcvt_s_d(numeric_limits<double>::min());}, + "fcvt.s.d, underflow"); + + // FCVT.D.S + expect<double>(D::number(0x4005BE76C0000000), + []{return D::fcvt_d_s(2.718);}, "fcvt.d.s"); + expect<bool>(true, []{ + double fd = D::fcvt_d_s(numeric_limits<float>::quiet_NaN()); + return D::isquietnan(fd); + }, "fcvt.d.s, quiet NaN"); + expect<bool>(true, []{ + double fd = D::fcvt_d_s(numeric_limits<float>::signaling_NaN()); + return D::isquietnan(fd); + }, "fcvt.d.s, signaling NaN"); + expect<double>(numeric_limits<double>::infinity(), + []{return D::fcvt_d_s(numeric_limits<float>::infinity());}, + "fcvt.d.s, infinity"); + + // FEQ.D + expect<bool>(true, []{return D::feq_d(1.414, 1.414);}, "feq.d, equal"); + expect<bool>(false,[]{return D::feq_d(2.718, 1.816);}, "feq.d, not equal"); + expect<bool>(true, []{return D::feq_d(0.0, -0.0);}, "feq.d, 0 == -0"); + expect<bool>(false, + []{return D::feq_d(numeric_limits<double>::quiet_NaN(), -1.0);}, + "feq.d, quiet NaN first"); + expect<bool>(false, + []{return D::feq_d(2.0, numeric_limits<double>::quiet_NaN());}, + "feq.d, quiet NaN second"); + expect<bool>(false, + []{return D::feq_d(numeric_limits<double>::quiet_NaN(), + numeric_limits<double>::quiet_NaN());}, + "feq.d, quiet NaN both"); + expect<bool>(false, + []{return D::feq_d(numeric_limits<double>::signaling_NaN(),-1.0);}, + "feq.d, signaling NaN first"); + expect<bool>(false, + []{return D::feq_d(2.0, numeric_limits<double>::signaling_NaN());}, + "feq.d, signaling NaN second"); + expect<bool>(false, + []{return D::feq_d(numeric_limits<double>::signaling_NaN(), + numeric_limits<double>::signaling_NaN());}, + "feq.d, signaling NaN both"); + + // FLT.D + expect<bool>(false, []{return D::flt_d(1.414, 1.414);}, "flt.d, equal"); + expect<bool>(true, []{return D::flt_d(1.816, 2.718);}, "flt.d, less"); + expect<bool>(false, []{return D::flt_d(2.718, 1.816);}, "flt.d, greater"); + expect<bool>(false, + []{return D::flt_d(numeric_limits<double>::quiet_NaN(), -1.0);}, + "flt.d, quiet NaN first"); + expect<bool>(false, + []{return D::flt_d(2.0, numeric_limits<double>::quiet_NaN());}, + "flt.d, quiet NaN second"); + expect<bool>(false, + []{return D::flt_d(numeric_limits<double>::quiet_NaN(), + numeric_limits<double>::quiet_NaN());}, + "flt.d, quiet NaN both"); + expect<bool>(false, + []{return D::flt_d(numeric_limits<double>::signaling_NaN(),-1.0);}, + "flt.d, signaling NaN first"); + expect<bool>(false, + []{return D::flt_d(2.0, numeric_limits<double>::signaling_NaN());}, + "flt.d, signaling NaN second"); + expect<bool>(false, + []{return D::flt_d(numeric_limits<double>::signaling_NaN(), + numeric_limits<double>::signaling_NaN());}, + "flt.d, signaling NaN both"); + + // FLE.D + expect<bool>(true, []{return D::fle_d(1.414, 1.414);}, "fle.d, equal"); + expect<bool>(true, []{return D::fle_d(1.816, 2.718);}, "fle.d, less"); + expect<bool>(false, []{return D::fle_d(2.718, 1.816);}, "fle.d, greater"); + expect<bool>(true, []{return D::fle_d(0.0, -0.0);}, "fle.d, 0 == -0"); + expect<bool>(false, + []{return D::fle_d(numeric_limits<double>::quiet_NaN(), -1.0);}, + "fle.d, quiet NaN first"); + expect<bool>(false, + []{return D::fle_d(2.0, numeric_limits<double>::quiet_NaN());}, + "fle.d, quiet NaN second"); + expect<bool>(false, + []{return D::fle_d(numeric_limits<double>::quiet_NaN(), + numeric_limits<double>::quiet_NaN());}, + "fle.d, quiet NaN both"); + expect<bool>(false, + []{return D::fle_d(numeric_limits<double>::signaling_NaN(),-1.0);}, + "fle.d, signaling NaN first"); + expect<bool>(false, + []{return D::fle_d(2.0, numeric_limits<double>::signaling_NaN());}, + "fle.d, signaling NaN second"); + expect<bool>(false, + []{return D::fle_d(numeric_limits<double>::signaling_NaN(), + numeric_limits<double>::signaling_NaN());}, + "fle.d, signaling NaN both"); + + // FCLASS.D + expect<uint64_t>(0x1, + []{return D::fclass_d(-numeric_limits<double>::infinity());}, + "fclass.d, -infinity"); + expect<uint64_t>(0x2, + []{return D::fclass_d(-3.14);}, "fclass.d, -normal"); + expect<uint64_t>(0x4, + []{return D::fclass_d(D::number(0x800FFFFFFFFFFFFFULL));}, + "fclass.d, -subnormal"); + expect<uint64_t>(0x8, []{return D::fclass_d(-0.0);}, "fclass.d, -0.0"); + expect<uint64_t>(0x10, []{return D::fclass_d(0.0);}, "fclass.d, 0.0"); + expect<uint64_t>(0x20, + []{return D::fclass_d(D::number(0x000FFFFFFFFFFFFFULL));}, + "fclass.d, subnormal"); + expect<uint64_t>(0x40, []{return D::fclass_d(1.816);}, "fclass.d, normal"); + expect<uint64_t>(0x80, + []{return D::fclass_d(numeric_limits<double>::infinity());}, + "fclass.d, infinity"); + expect<uint64_t>(0x100, + []{return D::fclass_d(numeric_limits<double>::signaling_NaN());}, + "fclass.d, signaling NaN"); + expect<uint64_t>(0x200, + []{return D::fclass_d(numeric_limits<double>::quiet_NaN());}, + "fclass.s, quiet NaN"); + + // FCVT.W.D + expect<int64_t>(256, []{return D::fcvt_w_d(256.3);}, + "fcvt.w.d, truncate positive"); + expect<int64_t>(-256, []{return D::fcvt_w_d(-256.2);}, + "fcvt.w.d, truncate negative"); + expect<int64_t>(0, []{return D::fcvt_w_d(0.0);}, "fcvt.w.d, 0.0"); + expect<int64_t>(0, []{return D::fcvt_w_d(-0.0);}, "fcvt.w.d, -0.0"); + expect<int64_t>(numeric_limits<int32_t>::max(), + []{return D::fcvt_w_d(numeric_limits<double>::max());}, + "fcvt.w.d, overflow"); + expect<int64_t>(0, []{return D::fcvt_w_d(numeric_limits<double>::min());}, + "fcvt.w.d, underflow"); + expect<int64_t>(numeric_limits<int32_t>::max(), + []{return D::fcvt_w_d(numeric_limits<double>::infinity());}, + "fcvt.w.d, infinity"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return D::fcvt_w_d(-numeric_limits<double>::infinity());}, + "fcvt.w.d, -infinity"); + expect<int64_t>(numeric_limits<int32_t>::max(), + []{return D::fcvt_w_d(numeric_limits<double>::quiet_NaN());}, + "fcvt.w.d, quiet NaN"); + expect<int64_t>(numeric_limits<int32_t>::max(), + []{return D::fcvt_w_d(-numeric_limits<double>::quiet_NaN());}, + "fcvt.w.d, quiet -NaN"); + expect<int64_t>(numeric_limits<int32_t>::max(), + []{return D::fcvt_w_d(numeric_limits<double>::signaling_NaN());}, + "fcvt.w.d, signaling NaN"); + + // FCVT.WU.D + expect<uint64_t>(256, []{return D::fcvt_wu_d(256.3);}, + "fcvt.wu.d, truncate positive"); + expect<uint64_t>(0, []{return D::fcvt_wu_d(-256.2);}, + "fcvt.wu.d, truncate negative"); + expect<uint64_t>(0, []{return D::fcvt_wu_d(0.0);}, "fcvt.wu.d, 0.0"); + expect<uint64_t>(0, []{return D::fcvt_wu_d(-0.0);}, "fcvt.wu.d, -0.0"); + expect<uint64_t>(numeric_limits<uint64_t>::max(), + []{return D::fcvt_wu_d(numeric_limits<double>::max());}, + "fcvt.wu.d, overflow"); + expect<uint64_t>(0,[]{return D::fcvt_wu_d(numeric_limits<double>::min());}, + "fcvt.wu.d, underflow"); + expect<uint64_t>(numeric_limits<uint64_t>::max(), + []{return D::fcvt_wu_d(numeric_limits<double>::infinity());}, + "fcvt.wu.d, infinity"); + expect<uint64_t>(0, + []{return D::fcvt_wu_d(-numeric_limits<double>::infinity());}, + "fcvt.wu.d, -infinity"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return D::fcvt_wu_d(numeric_limits<double>::quiet_NaN());}, + "fcvt.wu.d, quiet NaN"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return D::fcvt_wu_d(-numeric_limits<double>::quiet_NaN());}, + "fcvt.wu.d, quiet -NaN"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return D::fcvt_wu_d(numeric_limits<double>::signaling_NaN());}, + "fcvt.wu.d, signaling NaN"); + + // FCVT.D.W + expect<double>(0.0, []{return D::fcvt_d_w(0);}, "fcvt.d.w, 0"); + expect<double>(-2147483648.0, + []{return D::fcvt_d_w(numeric_limits<int32_t>::min());}, + "fcvt.d.w, negative"); + expect<double>(255.0, []{return D::fcvt_d_w(0xFFFFFFFF000000FFLL);}, + "fcvt.d.w, truncate"); + + // FCVT.D.WU + expect<double>(0.0, []{return D::fcvt_d_wu(0);}, "fcvt.d.wu, 0"); + expect<double>(2147483648.0, + []{return D::fcvt_d_wu(numeric_limits<int32_t>::min());}, + "fcvt.d.wu"); + expect<double>(255.0, + []{return D::fcvt_d_wu(0xFFFFFFFF000000FFLL);}, + "fcvt.d.wu, truncate"); + + // FCVT.L.D + expect<int64_t>(256, []{return D::fcvt_l_d(256.3);}, + "fcvt.l.d, truncate positive"); + expect<int64_t>(-256, []{return D::fcvt_l_d(-256.2);}, + "fcvt.l.d, truncate negative"); + expect<int64_t>(0, []{return D::fcvt_l_d(0.0);}, "fcvt.l.d, 0.0"); + expect<int64_t>(0, []{return D::fcvt_l_d(-0.0);}, "fcvt.l.d, -0.0"); + expect<int64_t>(-8589934592LL, []{return D::fcvt_l_d(-8589934592.0);}, + "fcvt.l.d, 32-bit overflow"); + expect<int64_t>(numeric_limits<int64_t>::max(), + []{return D::fcvt_l_d(numeric_limits<double>::max());}, + "fcvt.l.d, overflow"); + expect<int64_t>(0, []{return D::fcvt_l_d(numeric_limits<double>::min());}, + "fcvt.l.d, underflow"); + expect<int64_t>(numeric_limits<int64_t>::max(), + []{return D::fcvt_l_d(numeric_limits<double>::infinity());}, + "fcvt.l.d, infinity"); + expect<int64_t>(numeric_limits<int64_t>::min(), + []{return D::fcvt_l_d(-numeric_limits<double>::infinity());}, + "fcvt.l.d, -infinity"); + expect<int64_t>(numeric_limits<int64_t>::max(), + []{return D::fcvt_l_d(numeric_limits<double>::quiet_NaN());}, + "fcvt.l.d, quiet NaN"); + expect<int64_t>(numeric_limits<int64_t>::max(), + []{return D::fcvt_l_d(-numeric_limits<double>::quiet_NaN());}, + "fcvt.l.d, quiet -NaN"); + expect<int64_t>(numeric_limits<int64_t>::max(), + []{return D::fcvt_l_d(numeric_limits<double>::signaling_NaN());}, + "fcvt.l.d, signaling NaN"); + + // FCVT.LU.D + expect<uint64_t>(256, []{return D::fcvt_lu_d(256.3);}, + "fcvt.lu.d, truncate positive"); + expect<uint64_t>(0, []{return D::fcvt_lu_d(-256.2);}, + "fcvt.lu.d, truncate negative"); + expect<uint64_t>(0, []{return D::fcvt_lu_d(0.0);}, "fcvt.lu.d, 0.0"); + expect<uint64_t>(0, []{return D::fcvt_lu_d(-0.0);}, "fcvt.lu.d, -0.0"); + expect<uint64_t>(8589934592LL, []{return D::fcvt_lu_d(8589934592.0);}, + "fcvt.lu.d, 32-bit overflow"); + expect<uint64_t>(numeric_limits<uint64_t>::max(), + []{return D::fcvt_lu_d(numeric_limits<double>::max());}, + "fcvt.lu.d, overflow"); + expect<uint64_t>(0,[]{return D::fcvt_lu_d(numeric_limits<double>::min());}, + "fcvt.lu.d, underflow"); + expect<uint64_t>(numeric_limits<uint64_t>::max(), + []{return D::fcvt_lu_d(numeric_limits<double>::infinity());}, + "fcvt.lu.d, infinity"); + expect<uint64_t>(0, + []{return D::fcvt_lu_d(-numeric_limits<double>::infinity());}, + "fcvt.lu.d, -infinity"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return D::fcvt_lu_d(numeric_limits<double>::quiet_NaN());}, + "fcvt.lu.d, quiet NaN"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return D::fcvt_lu_d(-numeric_limits<double>::quiet_NaN());}, + "fcvt.lu.d, quiet -NaN"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return D::fcvt_lu_d(numeric_limits<double>::signaling_NaN());}, + "fcvt.lu.d, signaling NaN"); + + // FMV.X.D + expect<uint64_t>(0x40091EB851EB851FULL, []{return D::fmv_x_d(3.14);}, + "fmv.x.d, positive"); + expect<uint64_t>(0xC0091EB851EB851FULL, []{return D::fmv_x_d(-3.14);}, + "fmv.x.d, negative"); + expect<uint64_t>(0x0000000000000000ULL, []{return D::fmv_x_d(0.0);}, + "fmv.x.d, 0.0"); + expect<uint64_t>(0x8000000000000000ULL, []{return D::fmv_x_d(-0.0);}, + "fmv.x.d, -0.0"); + + // FCVT.D.L + expect<double>(0.0, []{return D::fcvt_d_l(0);}, "fcvt.d.l, 0"); + expect<double>(D::number(0xC3E0000000000000), + []{return D::fcvt_d_l(numeric_limits<int64_t>::min());}, + "fcvt.d.l, negative"); + expect<double>(D::number(0xC1EFFFFFE0200000), + []{return D::fcvt_d_l(0xFFFFFFFF000000FFLL);}, + "fcvt.d.l, 32-bit truncate"); + + // FCVT.D.LU + expect<double>(0.0, []{return D::fcvt_d_lu(0);}, "fcvt.d.lu, 0"); + expect<double>(D::number(0x43E0000000000000), + []{return D::fcvt_d_lu(numeric_limits<int64_t>::min());}, + "fcvt.d.lu"); + expect<double>(D::number(0x43EFFFFFFFE00000), + []{return D::fcvt_d_lu(0xFFFFFFFF000000FFLL);}, + "fcvt.d.lu, 32-bit truncate"); + + // FMV.D.X + expect<double>(-numeric_limits<float>::infinity(), + []{return D::fmv_d_x(0xFFF0000000000000ULL);}, "fmv.d.x"); + + return 0; +} diff --git a/tests/test-progs/insttest/src/riscv/rv64d.h b/tests/test-progs/insttest/src/riscv/rv64d.h new file mode 100644 index 000000000..d2c5898c4 --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/rv64d.h @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#pragma once + +#include <cstdint> +#include <limits> + +#include "insttest.h" + +namespace D +{ + +constexpr inline uint64_t +bits(double d) +{ + return reinterpret_cast<uint64_t&>(d); +} + +constexpr inline double +number(uint64_t b) +{ + return reinterpret_cast<double&>(b); +} + +inline bool +isquietnan(double f) +{ + return std::isnan(f) && (bits(f)&0x0008000000000000ULL) != 0; +} + +inline bool +issignalingnan(double f) +{ + return std::isnan(f) && (bits(f)&0x0008000000000000ULL) == 0; +} + +inline double +load(double mem) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + asm volatile("fld %0,%1" + : "=f" (fd) + : "m" (mem)); + return fd; +} + +inline double +store(double fs) +{ + double mem = std::numeric_limits<double>::signaling_NaN(); + asm volatile("fsd %1,%0" : "=m" (mem) : "f" (fs)); + return mem; +} + +inline double +fmadd_d(double fs1, double fs2, double fs3) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FR4OP("fmadd.d", fd, fs1, fs2, fs3); + return fd; +} + +inline double +fmsub_d(double fs1, double fs2, double fs3) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FR4OP("fmsub.d", fd, fs1, fs2, fs3); + return fd; +} + +inline double +fnmsub_d(double fs1, double fs2, double fs3) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FR4OP("fnmsub.d", fd, fs1, fs2, fs3); + return fd; +} + +inline double +fnmadd_d(double fs1, double fs2, double fs3) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FR4OP("fnmadd.d", fd, fs1, fs2, fs3); + return fd; +} + +inline double +fadd_d(double fs1, double fs2) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FROP("fadd.d", fd, fs1, fs2); + return fd; +} + +inline double +fsub_d(double fs1, double fs2) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FROP("fsub.d", fd, fs1, fs2); + return fd; +} + +inline double +fmul_d(double fs1, double fs2) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FROP("fmul.d", fd, fs1, fs2); + return fd; +} + +inline double +fdiv_d(double fs1, double fs2) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FROP("fdiv.d", fd, fs1, fs2); + return fd; +} + +inline double +fsqrt_d(double fs1) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + asm volatile("fsqrt.d %0,%1" : "=f" (fd) : "f" (fs1)); + return fd; +} + +inline double +fsgnj_d(double fs1, double fs2) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FROP("fsgnj.d", fd, fs1, fs2); + return fd; +} + +inline double +fsgnjn_d(double fs1, double fs2) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FROP("fsgnjn.d", fd, fs1, fs2); + return fd; +} + +inline double +fsgnjx_d(double fs1, double fs2) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FROP("fsgnjx.d", fd, fs1, fs2); + return fd; +} + +inline double +fmin_d(double fs1, double fs2) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FROP("fmin.d", fd, fs1, fs2); + return fd; +} + +inline double +fmax_d(double fs1, double fs2) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + FROP("fmax.d", fd, fs1, fs2); + return fd; +} + +inline float +fcvt_s_d(double fs1) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + asm volatile("fcvt.s.d %0,%1" : "=f" (fd) : "f" (fs1)); + return fd; +} + +inline double +fcvt_d_s(float fs1) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + asm volatile("fcvt.d.s %0,%1" : "=f" (fd) : "f" (fs1)); + return fd; +} + +inline bool +feq_d(double fs1, double fs2) +{ + bool rd = false; + asm volatile("feq.d %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2)); + return rd; +} + +inline bool +flt_d(double fs1, double fs2) +{ + bool rd = false; + asm volatile("flt.d %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2)); + return rd; +} + +inline bool +fle_d(double fs1, double fs2) +{ + bool rd = false; + asm volatile("fle.d %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2)); + return rd; +} + +inline uint64_t +fclass_d(double fs1) +{ + uint64_t rd = -1; + asm volatile("fclass.d %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline int64_t +fcvt_w_d(double fs1) +{ + int64_t rd = 0; + asm volatile("fcvt.w.d %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline uint64_t +fcvt_wu_d(double fs1) +{ + uint64_t rd = 0; + asm volatile("fcvt.wu.d %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline float +fcvt_d_w(int64_t rs1) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + asm volatile("fcvt.d.w %0,%1" : "=f" (fd) : "r" (rs1)); + return fd; +} + +inline double +fcvt_d_wu(uint64_t rs1) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + asm volatile("fcvt.d.wu %0,%1" : "=f" (fd) : "r" (rs1)); + return fd; +} + +inline int64_t +fcvt_l_d(double fs1) +{ + int64_t rd = 0; + asm volatile("fcvt.l.d %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline uint64_t +fcvt_lu_d(double fs1) +{ + uint64_t rd = 0; + asm volatile("fcvt.lu.d %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline uint64_t +fmv_x_d(double fs1) +{ + uint64_t rd = 0; + asm volatile("fmv.x.d %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline double +fcvt_d_l(int64_t rs1) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + asm volatile("fcvt.d.l %0,%1" : "=f" (fd) : "r" (rs1)); + return fd; +} + +inline double +fcvt_d_lu(uint64_t rs1) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + asm volatile("fcvt.d.lu %0,%1" : "=f" (fd) : "r" (rs1)); + return fd; +} + +inline double +fmv_d_x(uint64_t rs1) +{ + double fd = std::numeric_limits<double>::signaling_NaN(); + asm volatile("fmv.d.x %0,%1" : "=f" (fd) : "r" (rs1)); + return fd; +} + +} // namespace D diff --git a/tests/test-progs/insttest/src/riscv/rv64f.cpp b/tests/test-progs/insttest/src/riscv/rv64f.cpp new file mode 100644 index 000000000..f8b79f42a --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/rv64f.cpp @@ -0,0 +1,694 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#include <cstdint> +#include <limits> + +#include "insttest.h" +#include "rv64f.h" + +int main() +{ + using namespace std; + using namespace insttest; + + // FLAGS + expect<uint64_t>(0, []{ + F::fsflags(0); + return F::frflags(); + }, "clear fsflags"); + + // Memory + expect<float>(3.14, []{return F::load(3.14);}, "flw"); + expect<float>(1.816, []{return F::store(1.816);}, "fsw"); + + // FMADD.S + expect<float>(7.11624, []{return F::fmadd_s(3.14, 1.816, 1.414);}, + "fmadd.s"); + expect<bool>(true, []{ + float fd = F::fmadd_s(numeric_limits<float>::quiet_NaN(), 3.14, + 1.816); + return F::isquietnan(fd); + }, "fmadd.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fmadd_s(3.14, numeric_limits<float>::signaling_NaN(), + 1.816); + return F::isquietnan(fd); + }, "fmadd.s, signaling NaN"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fmadd_s(3.14, numeric_limits<float>::infinity(), + 1.414);}, + "fmadd.s, infinity"); + expect<float>(-numeric_limits<float>::infinity(), + []{return F::fmadd_s(3.14, -numeric_limits<float>::infinity(), + 1.414);}, + "fmadd.s, -infinity"); + + // FMSUB.S + expect<float>(4.28824, []{return F::fmsub_s(3.14, 1.816, 1.414);}, + "fmsub.s"); + expect<bool>(true, []{ + float fd = F::fmsub_s(3.14, numeric_limits<float>::quiet_NaN(), + 1.816); + return F::isquietnan(fd); + }, "fmsub.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fmsub_s(3.14, 1.816, + numeric_limits<float>::signaling_NaN()); + return F::isquietnan(fd); + }, "fmsub.s, signaling NaN"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fmsub_s(numeric_limits<float>::infinity(), 1.816, + 1.414);}, + "fmsub.s, infinity"); + expect<float>(-numeric_limits<float>::infinity(), + []{return F::fmsub_s(3.14, -numeric_limits<float>::infinity(), + 1.414);}, + "fmsub.s, -infinity"); + expect<float>(-numeric_limits<float>::infinity(), + []{return F::fmsub_s(3.14, 1.816, + numeric_limits<float>::infinity());}, + "fmsub.s, subtract infinity"); + + // FNMSUB.S + expect<float>(-4.28824, []{return F::fnmsub_s(3.14, 1.816, 1.414);}, + "fnmsub.s"); + expect<bool>(true, []{ + float fd = F::fnmsub_s(3.14, 1.816, + numeric_limits<float>::quiet_NaN()); + return F::isquietnan(fd); + }, "fnmsub.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fnmsub_s(numeric_limits<float>::signaling_NaN(), + 1.816, 1.414); + return F::isquietnan(fd); + }, "fnmsub.s, signaling NaN"); + expect<float>(-numeric_limits<float>::infinity(), + []{return F::fnmsub_s(numeric_limits<float>::infinity(), + 1.816, 1.414);}, + "fnmsub.s, infinity"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fnmsub_s(3.14, -numeric_limits<float>::infinity(), + 1.414);}, + "fnmsub.s, -infinity"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fnmsub_s(3.14, 1.816, + numeric_limits<float>::infinity());}, + "fnmsub.s, subtract infinity"); + + // FNMADD.S + expect<float>(-7.11624, []{return F::fnmadd_s(3.14, 1.816, 1.414);}, + "fnmadd.s"); + expect<bool>(true, []{ + float fd = F::fnmadd_s(numeric_limits<float>::quiet_NaN(), 3.14, + 1.816); + return F::isquietnan(fd); + }, "fnmadd.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fnmadd_s(3.14,numeric_limits<float>::signaling_NaN(), + 1.816); + return F::isquietnan(fd); + }, "fnmadd.s, signaling NaN"); + expect<float>(-numeric_limits<float>::infinity(), + []{return F::fnmadd_s(3.14, numeric_limits<float>::infinity(), + 1.414);}, + "fnmadd.s, infinity"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fnmadd_s(3.14, -numeric_limits<float>::infinity(), + 1.414);}, + "fnmadd.s, -infinity"); + + // FADD.S + expect<float>(4.554, []{return F::fadd_s(3.14, 1.414);}, "fadd.s"); + expect<bool>(true, []{ + float fd = F::fadd_s(numeric_limits<float>::quiet_NaN(), 1.414); + return F::isquietnan(fd); + }, "fadd.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fadd_s(3.14, numeric_limits<float>::signaling_NaN()); + return F::isquietnan(fd); + }, "fadd.s, signaling NaN"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fadd_s(3.14, numeric_limits<float>::infinity());}, + "fadd.s, infinity"); + expect<float>(-numeric_limits<float>::infinity(), + []{return F::fadd_s(-numeric_limits<float>::infinity(), 1.816);}, + "fadd.s, -infinity"); + + // FSUB.S + expect<float>(F::number(0xbfdced92), []{return F::fsub_s(1.414, 3.14);}, + "fsub.s"); + expect<bool>(true, []{ + float fd = F::fsub_s(numeric_limits<float>::quiet_NaN(), 1.414); + return F::isquietnan(fd); + }, "fsub.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fsub_s(3.14, numeric_limits<float>::signaling_NaN()); + return F::isquietnan(fd); + }, "fsub.s, signaling NaN"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fsub_s(numeric_limits<float>::infinity(), 3.14);}, + "fsub.s, infinity"); + expect<float>(-numeric_limits<float>::infinity(), + []{return F::fsub_s(-numeric_limits<float>::infinity(), 3.14);}, + "fsub.s, -infinity"); + expect<float>(-numeric_limits<float>::infinity(), + []{return F::fsub_s(1.414, numeric_limits<float>::infinity());}, + "fsub.s, subtract infinity"); + + // FMUL.S + expect<float>(F::number(0x4024573b), []{return F::fmul_s(1.816, 1.414);}, + "fmul.s"); + expect<bool>(true, []{ + float fd = F::fmul_s(numeric_limits<float>::quiet_NaN(), 1.414); + return F::isquietnan(fd); + }, "fmul.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fmul_s(1.816, + numeric_limits<float>::signaling_NaN()); + return F::isquietnan(fd); + }, "fmul.s, signaling NaN"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fmul_s(numeric_limits<float>::infinity(), 2.718);}, + "fmul.s, infinity"); + expect<float>(-numeric_limits<float>::infinity(), + []{return F::fmul_s(2.5966, -numeric_limits<float>::infinity());}, + "fmul.s, -infinity"); + expect<bool>(true, []{ + float fd = F::fmul_s(0.0, numeric_limits<float>::infinity()); + return F::isquietnan(fd); + }, "fmul.s, 0*infinity"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fmul_s(numeric_limits<float>::max(), 2.0);}, + "fmul.s, overflow"); + expect<float>(0.0, + []{return F::fmul_s(numeric_limits<float>::min(), + numeric_limits<float>::min());}, + "fmul.s, underflow"); + + // FDIV.S + expect<float>(2.5, []{return F::fdiv_s(10.0, 4.0);}, "fdiv.s"); + expect<bool>(true, []{ + float fd = F::fdiv_s(numeric_limits<float>::quiet_NaN(), 4.0); + return F::isquietnan(fd); + }, "fdiv.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fdiv_s(10.0, numeric_limits<float>::signaling_NaN()); + return F::isquietnan(fd); + }, "fdiv.s, signaling NaN"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fdiv_s(10.0, 0.0);}, "fdiv.s/0"); + expect<float>(0.0, + []{return F::fdiv_s(10.0, numeric_limits<float>::infinity());}, + "fdiv.s/infinity"); + expect<bool>(true, []{ + float fd = F::fdiv_s(numeric_limits<float>::infinity(), + numeric_limits<float>::infinity()); + return F::isquietnan(fd); + }, "fdiv.s, infinity/infinity"); + expect<bool>(true, []{ + float fd = F::fdiv_s(0.0, 0.0); + return F::isquietnan(fd); + }, "fdiv.s, 0/0"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fdiv_s(numeric_limits<float>::infinity(), 0.0);}, + "fdiv.s, infinity/0"); + expect<float>(0.0, + []{return F::fdiv_s(0.0, numeric_limits<float>::infinity());}, + "fdiv.s, 0/infinity"); + expect<float>(0.0, + []{return F::fdiv_s(numeric_limits<float>::min(), + numeric_limits<float>::max());}, + "fdiv.s, underflow"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fdiv_s(numeric_limits<float>::max(), + numeric_limits<float>::min());}, + "fdiv.s, overflow"); + + // FSQRT.S + expect<float>(0.3, []{return F::fsqrt_s(0.09);}, "fsqrt.s"); + expect<bool>(true, []{ + float fd = F::fsqrt_s(-1.0); + return F::isquietnan(fd); + }, "fsqrt.s, NaN"); + expect<bool>(true, []{ + float fd = F::fsqrt_s(numeric_limits<float>::quiet_NaN()); + return F::isquietnan(fd); + }, "fsqrt.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fsqrt_s(numeric_limits<float>::signaling_NaN()); + return F::isquietnan(fd); + }, "fsqrt.s, signaling NaN"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fsqrt_s(numeric_limits<float>::infinity());}, + "fsqrt.s, infinity"); + + // FSGNJ.S + expect<float>(1.0, []{return F::fsgnj_s(1.0, 25.0);}, "fsgnj.s, ++"); + expect<float>(-1.0, []{return F::fsgnj_s(1.0, -25.0);}, "fsgnj.s, +-"); + expect<float>(1.0, []{return F::fsgnj_s(-1.0, 25.0);}, "fsgnj.s, -+"); + expect<float>(-1.0, []{return F::fsgnj_s(-1.0, -25.0);}, "fsgnj.s, --"); + expect<bool>(true, []{ + float fd = F::fsgnj_s(numeric_limits<float>::quiet_NaN(), -4.0); + return F::isquietnan(fd); + }, "fsgnj.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fsgnj_s(numeric_limits<float>::signaling_NaN(), + -4.0); + return F::issignalingnan(fd); + }, "fsgnj.s, signaling NaN"); + expect<float>(4.0, []{return F::fsgnj_s(4.0, + numeric_limits<float>::quiet_NaN());}, "fsgnj.s, inject NaN"); + expect<float>(-4.0, + []{return F::fsgnj_s(4.0, -numeric_limits<float>::quiet_NaN());}, + "fsgnj.s, inject -NaN"); + + // FSGNJN.S + expect<float>(-1.0, []{return F::fsgnjn_s(1.0, 25.0);}, "fsgnjn.s, ++"); + expect<float>(1.0, []{return F::fsgnjn_s(1.0, -25.0);}, "fsgnjn.s, +-"); + expect<float>(-1.0, []{return F::fsgnjn_s(-1.0, 25.0);}, "fsgnjn.s, -+"); + expect<float>(1.0, []{return F::fsgnjn_s(-1.0, -25.0);}, "fsgnjn.s, --"); + expect<bool>(true, []{ + float fd = F::fsgnjn_s(numeric_limits<float>::quiet_NaN(), -4.0); + return F::isquietnan(fd); + }, "fsgnjn.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fsgnjn_s(numeric_limits<float>::signaling_NaN(), + -4.0); + return F::issignalingnan(fd); + }, "fsgnjn.s, signaling NaN"); + expect<float>(-4.0, + []{return F::fsgnjn_s(4.0, numeric_limits<float>::quiet_NaN());}, + "fsgnjn.s, inject NaN"); + expect<float>(4.0, + []{return F::fsgnjn_s(4.0, -numeric_limits<float>::quiet_NaN());}, + "fsgnjn.s, inject NaN"); + + // FSGNJX.S + expect<float>(1.0, []{return F::fsgnjx_s(1.0, 25.0);}, "fsgnjx.s, ++"); + expect<float>(-1.0, []{return F::fsgnjx_s(1.0, -25.0);}, "fsgnjx.s, +-"); + expect<float>(-1.0, []{return F::fsgnjx_s(-1.0, 25.0);}, "fsgnjx.s, -+"); + expect<float>(1.0, []{return F::fsgnjx_s(-1.0, -25.0);}, "fsgnjx.s, --"); + expect<bool>(true, []{ + float fd = F::fsgnjx_s(numeric_limits<float>::quiet_NaN(), -4.0); + return F::isquietnan(fd); + }, "fsgnjx.s, quiet NaN"); + expect<bool>(true, []{ + float fd = F::fsgnjx_s(numeric_limits<float>::signaling_NaN(), + -4.0); + return F::issignalingnan(fd); + }, "fsgnjx.s, signaling NaN"); + expect<float>(4.0, + []{return F::fsgnjx_s(4.0, numeric_limits<float>::quiet_NaN());}, + "fsgnjx.s, inject NaN"); + expect<float>(-4.0, + []{return F::fsgnjx_s(4.0, -numeric_limits<float>::quiet_NaN());}, + "fsgnjx.s, inject -NaN"); + + // FMIN.S + expect<float>(2.718, []{return F::fmin_s(3.14, 2.718);}, "fmin.s"); + expect<float>(-numeric_limits<float>::infinity(), + []{return F::fmin_s(-numeric_limits<float>::infinity(), + numeric_limits<float>::min());}, + "fmin.s, -infinity"); + expect<float>(numeric_limits<float>::max(), + []{return F::fmin_s(numeric_limits<float>::infinity(), + numeric_limits<float>::max());}, + "fmin.s, infinity"); + expect<float>(-1.414, + []{return F::fmin_s(numeric_limits<float>::quiet_NaN(), -1.414);}, + "fmin.s, quiet NaN first"); + expect<float>(2.718, + []{return F::fmin_s(2.718, numeric_limits<float>::quiet_NaN());}, + "fmin.s, quiet NaN second"); + expect<bool>(true, []{ + float fd = F::fmin_s(numeric_limits<float>::quiet_NaN(), + numeric_limits<float>::quiet_NaN()); + return F::isquietnan(fd); + }, "fmin.s, quiet NaN both"); + expect<float>(3.14, + []{return F::fmin_s(numeric_limits<float>::signaling_NaN(), + 3.14);}, + "fmin.s, signaling NaN first"); + expect<float>(1.816, + []{return F::fmin_s(1.816, + numeric_limits<float>::signaling_NaN());}, + "fmin.s, signaling NaN second"); + expect<bool>(true, []{ + float fd = F::fmin_s(numeric_limits<float>::signaling_NaN(), + numeric_limits<float>::signaling_NaN()); + return F::issignalingnan(fd); + }, "fmin.s, signaling NaN both"); + + // FMAX.S + expect<float>(3.14, []{return F::fmax_s(3.14, 2.718);}, "fmax.s"); + expect<float>(numeric_limits<float>::min(), + []{return F::fmax_s(-numeric_limits<float>::infinity(), + numeric_limits<float>::min());}, + "fmax.s, -infinity"); + expect<float>(numeric_limits<float>::infinity(), + []{return F::fmax_s(numeric_limits<float>::infinity(), + numeric_limits<float>::max());}, + "fmax.s, infinity"); + expect<float>(-1.414, + []{return F::fmax_s(numeric_limits<float>::quiet_NaN(), -1.414);}, + "fmax.s, quiet NaN first"); + expect<float>(2.718, + []{return F::fmax_s(2.718, numeric_limits<float>::quiet_NaN());}, + "fmax.s, quiet NaN second"); + expect<bool>(true, []{ + float fd = F::fmax_s(numeric_limits<float>::quiet_NaN(), + numeric_limits<float>::quiet_NaN()); + return F::isquietnan(fd); + }, "fmax.s, quiet NaN both"); + expect<float>(3.14, + []{return F::fmax_s(numeric_limits<float>::signaling_NaN(), + 3.14);}, + "fmax.s, signaling NaN first"); + expect<float>(1.816, []{return F::fmax_s(1.816, + numeric_limits<float>::signaling_NaN());}, + "fmax.s, signaling NaN second"); + expect<bool>(true, []{ + float fd = F::fmax_s(numeric_limits<float>::signaling_NaN(), + numeric_limits<float>::signaling_NaN()); + return F::issignalingnan(fd); + }, "fmax.s, signaling NaN both"); + + // FCVT.W.S + expect<int64_t>(256, []{return F::fcvt_w_s(256.3);}, + "fcvt.w.s, truncate positive"); + expect<int64_t>(-256, []{return F::fcvt_w_s(-256.2);}, + "fcvt.w.s, truncate negative"); + expect<int64_t>(0, []{return F::fcvt_w_s(0.0);}, "fcvt.w.s, 0.0"); + expect<int64_t>(0, []{return F::fcvt_w_s(-0.0);}, "fcvt.w.s, -0.0"); + expect<int64_t>(numeric_limits<int32_t>::max(), + []{return F::fcvt_w_s(numeric_limits<float>::max());}, + "fcvt.w.s, overflow"); + expect<int64_t>(0, []{return F::fcvt_w_s(numeric_limits<float>::min());}, + "fcvt.w.s, underflow"); + expect<int64_t>(numeric_limits<int32_t>::max(), + []{return F::fcvt_w_s(numeric_limits<float>::infinity());}, + "fcvt.w.s, infinity"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return F::fcvt_w_s(-numeric_limits<float>::infinity());}, + "fcvt.w.s, -infinity"); + expect<int64_t>(numeric_limits<int32_t>::max(), + []{return F::fcvt_w_s(numeric_limits<float>::quiet_NaN());}, + "fcvt.w.s, quiet NaN"); + expect<int64_t>(numeric_limits<int32_t>::max(), + []{return F::fcvt_w_s(-numeric_limits<float>::quiet_NaN());}, + "fcvt.w.s, quiet -NaN"); + expect<int64_t>(numeric_limits<int32_t>::max(), + []{return F::fcvt_w_s(numeric_limits<float>::signaling_NaN());}, + "fcvt.w.s, signaling NaN"); + + // FCVT.WU.S + expect<uint64_t>(256, []{return F::fcvt_wu_s(256.3);}, + "fcvt.wu.s, truncate positive"); + expect<uint64_t>(0, []{return F::fcvt_wu_s(-256.2);}, + "fcvt.wu.s, truncate negative"); + expect<uint64_t>(0, []{return F::fcvt_wu_s(0.0);}, "fcvt.wu.s, 0.0"); + expect<uint64_t>(0, []{return F::fcvt_wu_s(-0.0);}, "fcvt.wu.s, -0.0"); + expect<uint64_t>(numeric_limits<uint64_t>::max(), + []{return F::fcvt_wu_s(numeric_limits<float>::max());}, + "fcvt.wu.s, overflow"); + expect<uint64_t>(0, []{return F::fcvt_wu_s(numeric_limits<float>::min());}, + "fcvt.wu.s, underflow"); + expect<uint64_t>(numeric_limits<uint64_t>::max(), + []{return F::fcvt_wu_s(numeric_limits<float>::infinity());}, + "fcvt.wu.s, infinity"); + expect<uint64_t>(0, + []{return F::fcvt_wu_s(-numeric_limits<float>::infinity());}, + "fcvt.wu.s, -infinity"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return F::fcvt_wu_s(numeric_limits<float>::quiet_NaN());}, + "fcvt.wu.s, quiet NaN"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return F::fcvt_wu_s(-numeric_limits<float>::quiet_NaN());}, + "fcvt.wu.s, quiet -NaN"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return F::fcvt_wu_s(numeric_limits<float>::signaling_NaN());}, + "fcvt.wu.s, signaling NaN"); + + // FMV.X.S + expect<uint64_t>(0x000000004048F5C3ULL, []{return F::fmv_x_s(3.14);}, + "fmv.x.s, positive"); + expect<uint64_t>(0xFFFFFFFFC048F5C3ULL, []{return F::fmv_x_s(-3.14);}, + "fmv.x.s, negative"); + expect<uint64_t>(0x0000000000000000ULL, []{return F::fmv_x_s(0.0);}, + "fmv.x.s, 0.0"); + expect<uint64_t>(0xFFFFFFFF80000000ULL, []{return F::fmv_x_s(-0.0);}, + "fmv.x.s, -0.0"); + + // FEQ.S + expect<bool>(true, []{return F::feq_s(1.414, 1.414);}, "feq.s, equal"); + expect<bool>(false, []{return F::feq_s(2.718, 1.816);}, + "feq.s, not equal"); + expect<bool>(true, []{return F::feq_s(0.0, -0.0);}, "feq.s, 0 == -0"); + expect<bool>(false, + []{return F::feq_s(numeric_limits<float>::quiet_NaN(), -1.0);}, + "feq.s, quiet NaN first"); + expect<bool>(false, + []{return F::feq_s(2.0, numeric_limits<float>::quiet_NaN());}, + "feq.s, quiet NaN second"); + expect<bool>(false, + []{return F::feq_s(numeric_limits<float>::quiet_NaN(), + numeric_limits<float>::quiet_NaN());}, + "feq.s, quiet NaN both"); + expect<bool>(false, + []{return F::feq_s(numeric_limits<float>::signaling_NaN(), -1.0);}, + "feq.s, signaling NaN first"); + expect<bool>(false, + []{return F::feq_s(2.0, numeric_limits<float>::signaling_NaN());}, + "feq.s, signaling NaN second"); + expect<bool>(false, + []{return F::feq_s(numeric_limits<float>::signaling_NaN(), + numeric_limits<float>::signaling_NaN());}, + "feq.s, signaling NaN both"); + + // FLT.S + expect<bool>(false, []{return F::flt_s(1.414, 1.414);}, "flt.s, equal"); + expect<bool>(true, []{return F::flt_s(1.816, 2.718);}, "flt.s, less"); + expect<bool>(false, []{return F::flt_s(2.718, 1.816);}, "flt.s, greater"); + expect<bool>(false, + []{return F::flt_s(numeric_limits<float>::quiet_NaN(), -1.0);}, + "flt.s, quiet NaN first"); + expect<bool>(false, + []{return F::flt_s(2.0, numeric_limits<float>::quiet_NaN());}, + "flt.s, quiet NaN second"); + expect<bool>(false, + []{return F::flt_s(numeric_limits<float>::quiet_NaN(), + numeric_limits<float>::quiet_NaN());}, + "flt.s, quiet NaN both"); + expect<bool>(false, + []{return F::flt_s(numeric_limits<float>::signaling_NaN(), -1.0);}, + "flt.s, signaling NaN first"); + expect<bool>(false, + []{return F::flt_s(2.0, numeric_limits<float>::signaling_NaN());}, + "flt.s, signaling NaN second"); + expect<bool>(false, + []{return F::flt_s(numeric_limits<float>::signaling_NaN(), + numeric_limits<float>::signaling_NaN());}, + "flt.s, signaling NaN both"); + + // FLE.S + expect<bool>(true, []{return F::fle_s(1.414, 1.414);}, "fle.s, equal"); + expect<bool>(true, []{return F::fle_s(1.816, 2.718);}, "fle.s, less"); + expect<bool>(false, []{return F::fle_s(2.718, 1.816);}, "fle.s, greater"); + expect<bool>(true, []{return F::fle_s(0.0, -0.0);}, "fle.s, 0 == -0"); + expect<bool>(false, + []{return F::fle_s(numeric_limits<float>::quiet_NaN(), -1.0);}, + "fle.s, quiet NaN first"); + expect<bool>(false, + []{return F::fle_s(2.0, numeric_limits<float>::quiet_NaN());}, + "fle.s, quiet NaN second"); + expect<bool>(false, + []{return F::fle_s(numeric_limits<float>::quiet_NaN(), + numeric_limits<float>::quiet_NaN());}, + "fle.s, quiet NaN both"); + expect<bool>(false, + []{return F::fle_s(numeric_limits<float>::signaling_NaN(), -1.0);}, + "fle.s, signaling NaN first"); + expect<bool>(false, + []{return F::fle_s(2.0, numeric_limits<float>::signaling_NaN());}, + "fle.s, signaling NaN second"); + expect<bool>(false, + []{return F::fle_s(numeric_limits<float>::signaling_NaN(), + numeric_limits<float>::signaling_NaN());}, + "fle.s, signaling NaN both"); + + // FCLASS.S + expect<uint64_t>(0x1, + []{return F::fclass_s(-numeric_limits<float>::infinity());}, + "fclass.s, -infinity"); + expect<uint64_t>(0x2, []{return F::fclass_s(-3.14);}, "fclass.s, -normal"); + expect<uint64_t>(0x4, []{return F::fclass_s(F::number(0x807FFFFF));}, + "fclass.s, -subnormal"); + expect<uint64_t>(0x8, []{return F::fclass_s(-0.0);}, "fclass.s, -0.0"); + expect<uint64_t>(0x10, []{return F::fclass_s(0.0);}, "fclass.s, 0.0"); + expect<uint64_t>(0x20, []{return F::fclass_s(F::number(0x007FFFFF));}, + "fclass.s, subnormal"); + expect<uint64_t>(0x40, []{return F::fclass_s(1.816);}, "fclass.s, normal"); + expect<uint64_t>(0x80, + []{return F::fclass_s(numeric_limits<float>::infinity());}, + "fclass.s, infinity"); + expect<uint64_t>(0x100, + []{return F::fclass_s(numeric_limits<float>::signaling_NaN());}, + "fclass.s, signaling NaN"); + expect<uint64_t>(0x200, + []{return F::fclass_s(numeric_limits<float>::quiet_NaN());}, + "fclass.s, quiet NaN"); + + // FCVT.S.W + expect<float>(0.0, []{return F::fcvt_s_w(0);}, "fcvt.s.w, 0"); + expect<float>(-2147483648.0, + []{return F::fcvt_s_w(numeric_limits<int32_t>::min());}, + "fcvt.s.w, negative"); + expect<float>(255.0, []{return F::fcvt_s_w(0xFFFFFFFF000000FFLL);}, + "fcvt.s.w, truncate"); + + // FCVT.S.WU + expect<float>(0.0, []{return F::fcvt_s_wu(0);}, "fcvt.s.wu, 0"); + expect<float>(2147483648.0, + []{return F::fcvt_s_wu(numeric_limits<int32_t>::min());}, + "fcvt.s.wu"); + expect<float>(255.0, []{return F::fcvt_s_wu(0xFFFFFFFF000000FFLL);}, + "fcvt.s.wu, truncate"); + + // FMV.S.X + expect<float>(numeric_limits<float>::infinity(), + []{return F::fmv_s_x(0x7F800000);}, "fmv.s.x"); + expect<float>(-0.0, []{return F::fmv_s_x(0xFFFFFFFF80000000ULL);}, + "fmv.s.x, truncate"); + + // FCSR functions + int rm = F::frrm(); + expect<uint64_t>(0x7, []{ // FSRM + F::fsrm(-1); + return F::frrm(); + }, "fsrm"); + expect<uint64_t>(0x1F, []{ // FSFLAGS + F::fsflags(0); + F::fsflags(-1); + return F::frflags(); + }, "fsflags"); + expect<uint64_t>(0xFF, []{ // FSCSR + F::fsflags(0); + F::fsrm(0); + F::fscsr(-1); + return F::frcsr(); + }, "fscsr"); + expect<int>(rm << 5, [=]{ + F::fscsr(0); + F::fsrm(rm); + return F::frcsr(); + }, "restore initial round mode"); + + F::fsflags(0); + + // FCVT.L.S + expect<int64_t>(256, []{return F::fcvt_l_s(256.3);}, + "fcvt.l.s, truncate positive"); + expect<int64_t>(-256, []{return F::fcvt_l_s(-256.2);}, + "fcvt.l.s, truncate negative"); + expect<int64_t>(0, []{return F::fcvt_l_s(0.0);}, "fcvt.l.s, 0.0"); + expect<int64_t>(0, []{return F::fcvt_l_s(-0.0);}, "fcvt.l.s, -0.0"); + expect<int64_t>(-8589934592LL, []{return F::fcvt_l_s(-8589934592.0);}, + "fcvt.l.s, 32-bit overflow"); + expect<int64_t>(numeric_limits<int64_t>::max(), + []{return F::fcvt_l_s(numeric_limits<float>::max());}, + "fcvt.l.s, overflow"); + expect<int64_t>(0, []{return F::fcvt_l_s(numeric_limits<float>::min());}, + "fcvt.l.s, underflow"); + expect<int64_t>(numeric_limits<int64_t>::max(), + []{return F::fcvt_l_s(numeric_limits<float>::infinity());}, + "fcvt.l.s, infinity"); + expect<int64_t>(numeric_limits<int64_t>::min(), + []{return F::fcvt_l_s(-numeric_limits<float>::infinity());}, + "fcvt.l.s, -infinity"); + expect<int64_t>(numeric_limits<int64_t>::max(), + []{return F::fcvt_l_s(numeric_limits<float>::quiet_NaN());}, + "fcvt.l.s, quiet NaN"); + expect<int64_t>(numeric_limits<int64_t>::max(), + []{return F::fcvt_l_s(-numeric_limits<float>::quiet_NaN());}, + "fcvt.l.s, quiet -NaN"); + expect<int64_t>(numeric_limits<int64_t>::max(), + []{return F::fcvt_l_s(numeric_limits<float>::signaling_NaN());}, + "fcvt.l.s, signaling NaN"); + + // FCVT.LU.S + expect<uint64_t>(256, []{return F::fcvt_lu_s(256.3);}, + "fcvt.lu.s, truncate positive"); + expect<uint64_t>(0, []{return F::fcvt_lu_s(-256.2);}, + "fcvt.lu.s, truncate negative"); + expect<uint64_t>(0, []{return F::fcvt_lu_s(0.0);}, "fcvt.lu.s, 0.0"); + expect<uint64_t>(0, []{return F::fcvt_lu_s(-0.0);}, "fcvt.lu.s, -0.0"); + expect<uint64_t>(8589934592LL, + []{return F::fcvt_lu_s(8589934592.0);}, + "fcvt.lu.s, 32-bit overflow"); + expect<uint64_t>(numeric_limits<uint64_t>::max(), + []{return F::fcvt_lu_s(numeric_limits<float>::max());}, + "fcvt.lu.s, overflow"); + expect<uint64_t>(0, []{return F::fcvt_lu_s(numeric_limits<float>::min());}, + "fcvt.lu.s, underflow"); + expect<uint64_t>(numeric_limits<uint64_t>::max(), + []{return F::fcvt_lu_s(numeric_limits<float>::infinity());}, + "fcvt.lu.s, infinity"); + expect<uint64_t>(0, + []{return F::fcvt_lu_s(-numeric_limits<float>::infinity());}, + "fcvt.lu.s, -infinity"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return F::fcvt_lu_s(numeric_limits<float>::quiet_NaN());}, + "fcvt.lu.s, quiet NaN"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return F::fcvt_lu_s(-numeric_limits<float>::quiet_NaN());}, + "fcvt.lu.s, quiet -NaN"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL, + []{return F::fcvt_lu_s(numeric_limits<float>::signaling_NaN());}, + "fcvt.lu.s, signaling NaN"); + + // FCVT.S.L + expect<float>(0.0, []{return F::fcvt_s_l(0);}, "fcvt.s.l, 0"); + expect<float>(-9.223372e18, + []{return F::fcvt_s_l(numeric_limits<int64_t>::min());}, + "fcvt.s.l, negative"); + expect<float>(-4.29496704e9, []{return F::fcvt_s_l(0xFFFFFFFF000000FFLL);}, + "fcvt.s.l, 32-bit truncate"); + + // FCVT.S.LU + expect<float>(0.0, []{return F::fcvt_s_lu(0);}, "fcvt.s.lu, 0"); + expect<float>(9.223372e18, + []{return F::fcvt_s_lu(numeric_limits<int64_t>::min());}, + "fcvt.s.lu"); + expect<float>(1.8446744e19, []{return F::fcvt_s_lu(0xFFFFFFFF000000FFLL);}, + "fcvt.s.lu, 32-bit truncate"); + + return 0; +} diff --git a/tests/test-progs/insttest/src/riscv/rv64f.h b/tests/test-progs/insttest/src/riscv/rv64f.h new file mode 100644 index 000000000..5a6798cc6 --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/rv64f.h @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#pragma once + +#include <cstdint> +#include <limits> + +#include "insttest.h" + +namespace F +{ + +constexpr inline uint32_t +bits(float f) +{ + return reinterpret_cast<uint32_t&>(f); +} + +constexpr inline float +number(uint32_t b) +{ + return reinterpret_cast<float&>(b); +} + +inline bool +isquietnan(float f) +{ + return std::isnan(f) && (bits(f)&0x00400000) != 0; +} + +inline bool +issignalingnan(float f) +{ + return std::isnan(f) && (bits(f)&0x00400000) == 0; +} + +inline float +load(float mem) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + asm volatile("flw %0,%1" + : "=f" (fd) + : "m" (mem)); + return fd; +} + +inline float +store(float fs) +{ + float mem = std::numeric_limits<float>::signaling_NaN(); + asm volatile("fsw %1,%0" : "=m" (mem) : "f" (fs)); + return mem; +} + +inline uint64_t +frflags() +{ + uint64_t rd = -1; + asm volatile("frflags %0" : "=r" (rd)); + return rd; +} + +inline uint64_t +fsflags(uint64_t rs1) +{ + uint64_t rd = -1; + asm volatile("fsflags %0,%1" : "=r" (rd) : "r" (rs1)); + return rd; +} + +inline float +fmadd_s(float fs1, float fs2, float fs3) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FR4OP("fmadd.s", fd, fs1, fs2, fs3); + return fd; +} + +inline float +fmsub_s(float fs1, float fs2, float fs3) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FR4OP("fmsub.s", fd, fs1, fs2, fs3); + return fd; +} + +inline float +fnmsub_s(float fs1, float fs2, float fs3) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FR4OP("fnmsub.s", fd, fs1, fs2, fs3); + return fd; +} + +inline float +fnmadd_s(float fs1, float fs2, float fs3) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FR4OP("fnmadd.s", fd, fs1, fs2, fs3); + return fd; +} + +inline float +fadd_s(float fs1, float fs2) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FROP("fadd.s", fd, fs1, fs2); + return fd; +} + +inline float +fsub_s(float fs1, float fs2) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FROP("fsub.s", fd, fs1, fs2); + return fd; +} + +inline float +fmul_s(float fs1, float fs2) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FROP("fmul.s", fd, fs1, fs2); + return fd; +} + +inline float +fdiv_s(float fs1, float fs2) +{ + + float fd = 0.0; + FROP("fdiv.s", fd, fs1, fs2); + return fd; +} + +inline float +fsqrt_s(float fs1) +{ + float fd = std::numeric_limits<float>::infinity(); + asm volatile("fsqrt.s %0,%1" : "=f" (fd) : "f" (fs1)); + return fd; +} + +inline float +fsgnj_s(float fs1, float fs2) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FROP("fsgnj.s", fd, fs1, fs2); + return fd; +} + +inline float +fsgnjn_s(float fs1, float fs2) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FROP("fsgnjn.s", fd, fs1, fs2); + return fd; +} + +inline float +fsgnjx_s(float fs1, float fs2) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FROP("fsgnjx.s", fd, fs1, fs2); + return fd; +} + +inline float +fmin_s(float fs1, float fs2) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FROP("fmin.s", fd, fs1, fs2); + return fd; +} + +inline float +fmax_s(float fs1, float fs2) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + FROP("fmax.s", fd, fs1, fs2); + return fd; +} + +inline int64_t +fcvt_w_s(float fs1) +{ + int64_t rd = 0; + asm volatile("fcvt.w.s %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline uint64_t +fcvt_wu_s(float fs1) +{ + uint64_t rd = 0; + asm volatile("fcvt.wu.s %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline uint64_t +fmv_x_s(float fs1) +{ + uint64_t rd = 0; + asm volatile("fmv.x.s %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline bool +feq_s(float fs1, float fs2) +{ + bool rd = false; + asm volatile("feq.s %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2)); + return rd; +} + +inline bool +flt_s(float fs1, float fs2) +{ + bool rd = false; + asm volatile("flt.s %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2)); + return rd; +} + +inline bool +fle_s(float fs1, float fs2) +{ + bool rd = false; + asm volatile("fle.s %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2)); + return rd; +} + +inline uint64_t +fclass_s(float fs1) +{ + uint64_t rd = -1; + asm volatile("fclass.s %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline float +fcvt_s_w(int64_t rs1) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + asm volatile("fcvt.s.w %0,%1" : "=f" (fd) : "r" (rs1)); + return fd; +} + +inline float +fcvt_s_wu(uint64_t rs1) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + asm volatile("fcvt.s.wu %0,%1" : "=f" (fd) : "r" (rs1)); + return fd; +} + +inline float +fmv_s_x(uint64_t rs1) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + asm volatile("fmv.s.x %0,%1" : "=f" (fd) : "r" (rs1)); + return fd; +} + +inline uint64_t +frcsr() +{ + uint64_t rd = -1; + asm volatile("frcsr %0" : "=r" (rd)); + return rd; +} + +inline uint64_t +frrm() +{ + uint64_t rd = -1; + asm volatile("frrm %0" : "=r" (rd)); + return rd; +} + +inline uint64_t +fscsr(uint64_t rs1) +{ + uint64_t rd = -1; + asm volatile("fscsr %0,%1" : "=r" (rd) : "r" (rs1)); + return rd; +} + +inline uint64_t +fsrm(uint64_t rs1) +{ + uint64_t rd = -1; + asm volatile("fsrm %0,%1" : "=r" (rd) : "r" (rs1)); + return rd; +} + +inline int64_t +fcvt_l_s(float fs1) +{ + int64_t rd = 0; + asm volatile("fcvt.l.s %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline uint64_t +fcvt_lu_s(float fs1) +{ + + int64_t rd = 0; + asm volatile("fcvt.lu.s %0,%1" : "=r" (rd) : "f" (fs1)); + return rd; +} + +inline float +fcvt_s_l(int64_t rs1) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + asm volatile("fcvt.s.l %0,%1" : "=f" (fd) : "r" (rs1)); + return fd; +} + +inline float +fcvt_s_lu(uint64_t rs1) +{ + float fd = std::numeric_limits<float>::signaling_NaN(); + asm volatile("fcvt.s.lu %0,%1" : "=f" (fd) : "r" (rs1)); + return fd; +} + +} // namespace F diff --git a/tests/test-progs/insttest/src/riscv/rv64i.cpp b/tests/test-progs/insttest/src/riscv/rv64i.cpp new file mode 100644 index 000000000..95e8ee02a --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/rv64i.cpp @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/times.h> +#include <sys/types.h> +#include <unistd.h> + +#include <cstdint> +#include <cstring> +#include <iostream> +#include <limits> + +#include "insttest.h" +#include "rv64i.h" + +int main() +{ + using namespace std; + using namespace insttest; + + // LUI + expect<int64_t>(4096, []{return I::lui(1);}, "lui"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::lui(0x80000);}, "lui, negative"); + + // AUIPC + expect<bool>(true, []{return I::auipc(3);}, "auipc"); + + // Jump (JAL, JALR) + expect<bool>(true, []{return I::jal();}, "jal"); + expect<bool>(true, []{return I::jalr();}, "jalr"); + + // BEQ + expect<bool>(true, []{return I::beq(5, 5);}, "beq, equal"); + expect<bool>(false, []{return I::beq(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "beq, not equal"); + + // BNE + expect<bool>(false, []{return I::bne(5, 5);}, "bne, equal"); + expect<bool>(true, []{return I::bne(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "bne, not equal"); + + // BLT + expect<bool>(true, []{return I::blt(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::max());}, "blt, less"); + expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::min());}, "blt, equal"); + expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "blt, greater"); + + // BGE + expect<bool>(false, []{return I::bge(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::max());}, "bge, less"); + expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::min());}, "bge, equal"); + expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "bge, greater"); + + // BLTU + expect<bool>(true, []{return I::blt(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::max());}, "bltu, greater"); + expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::min());}, "bltu, equal"); + expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "bltu, less"); + + // BGEU + expect<bool>(false, []{return I::bge(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::max());}, "bgeu, greater"); + expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::min());}, "bgeu, equal"); + expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "bgeu, less"); + + // Load (LB, LH, LW, LBU, LHU) + expect<int64_t>(7, []{return I::load<int8_t, int64_t>(0x07);}, + "lb, positive"); + expect<int64_t>(numeric_limits<int8_t>::min(), + []{return I::load<int8_t, int64_t>(0x80);}, "lb, negative"); + expect<int64_t>(1792, []{return I::load<int16_t, int64_t>(0x0700);}, + "lh, positive"); + expect<int64_t>(numeric_limits<int16_t>::min(), + []{return I::load<int16_t, int64_t>(0x8000);}, "lh, negative"); + expect<int64_t>(458752, []{return I::load<int32_t, int64_t>(0x00070000);}, + "lw, positive"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::load<int32_t, int64_t>(0x80000000);}, + "lw, negative"); + expect<uint64_t>(128, []{return I::load<uint8_t, uint64_t>(0x80);}, "lbu"); + expect<uint64_t>(32768, []{return I::load<uint16_t, uint64_t>(0x8000);}, + "lhu"); + + // Store (SB, SH, SW) + expect<uint8_t>(0xFF, []{return I::store<int8_t>(-1);}, "sb"); + expect<uint16_t>(0xFFFF, []{return I::store<int16_t>(-1);}, "sh"); + expect<uint32_t>(0xFFFFFFFF, []{return I::store<int32_t>(-1);}, "sw"); + + // ADDI + expect<int64_t>(1073742078, []{return I::addi(0x3FFFFFFF, 255);}, + "addi"); + expect<int64_t>(1, []{return I::addi(-1, 2);}, "addi, overflow"); + + // SLTI + expect<bool>(true, []{return I::slti(-1, 0);}, "slti, true"); + expect<bool>(false, []{return I::slti(0, -1);}, "slti, false"); + + // SLTIU + expect<bool>(false, []{return I::sltiu(-1, 0);}, "sltiu, false"); + expect<bool>(true, []{return I::sltiu(0, -1);}, "sltiu, true"); + + // XORI + expect<uint64_t>(0xFF, []{return I::xori(0xAA, 0x55);}, "xori (1)"); + expect<uint64_t>(0, []{return I::xori(0xAA, 0xAA);}, "xori (0)"); + + // ORI + expect<uint64_t>(0xFF, []{return I::ori(0xAA, 0x55);}, "ori (1)"); + expect<uint64_t>(0xAA, []{return I::ori(0xAA, 0xAA);}, "ori (A)"); + + // ANDI + expect<uint64_t>(0, []{return I::andi(-1, 0);}, "andi (0)"); + expect<uint64_t>(0x1234567812345678ULL, + []{return I::andi(0x1234567812345678ULL, -1);}, "andi (1)"); + + // SLLI + expect<int64_t>(65280, []{return I::slli(255, 8);}, "slli, general"); + expect<int64_t>(numeric_limits<int64_t>::min(), + []{return I::slli(255, 63);}, "slli, erase"); + + // SRLI + expect<int64_t>(255, []{return I::srli(65280, 8);}, "srli, general"); + expect<int64_t>(0, []{return I::srli(255, 8);}, "srli, erase"); + expect<int64_t>(1, []{return I::srli(numeric_limits<int64_t>::min(), 63);}, + "srli, negative"); + + // SRAI + expect<int64_t>(255, []{return I::srai(65280, 8);}, "srai, general"); + expect<int64_t>(0, []{return I::srai(255, 8);}, "srai, erase"); + expect<int64_t>(-1, + []{return I::srai(numeric_limits<int64_t>::min(), 63);}, + "srai, negative"); + + // ADD + expect<int64_t>(1073742078, []{return I::add(0x3FFFFFFF, 255);}, "add"); + expect<int64_t>(-1, + []{return I::add(0x7FFFFFFFFFFFFFFFLL, 0x8000000000000000LL);}, + "add, overflow"); + + // SUB + expect<int64_t>(65535, []{return I::sub(65536, 1);}, "sub"); + expect<int64_t>(-1, + []{return I::sub(0x7FFFFFFFFFFFFFFFLL, 0x8000000000000000LL);}, + "sub, \"overflow\""); + + // SLL + expect<int64_t>(65280, []{return I::sll(255, 8);}, "sll, general"); + expect<int64_t>(numeric_limits<int64_t>::min(), + []{return I::sll(255, 63);}, "sll, erase"); + + // SLT + expect<bool>(true, []{return I::slt(-1, 0);}, "slt, true"); + expect<bool>(false, []{return I::slt(0, -1);}, "slt, false"); + + // SLTU + expect<bool>(false, []{return I::sltu(-1, 0);}, "sltu, false"); + expect<bool>(true, []{return I::sltu(0, -1);}, "sltu, true"); + + // XOR + expect<uint64_t>(-1, + []{return I::xor_inst(0xAAAAAAAAAAAAAAAAULL, + 0x5555555555555555ULL);}, + "xor (1)"); + expect<uint64_t>(0, + []{return I::xor_inst(0xAAAAAAAAAAAAAAAAULL, + 0xAAAAAAAAAAAAAAAAULL);}, + "xor (0)"); + + // SRL + expect<uint64_t>(255, []{return I::srl(65280, 8);}, "srl, general"); + expect<uint64_t>(0, []{return I::srl(255, 8);}, "srl, erase"); + expect<uint64_t>(1, []{return I::srl(numeric_limits<int64_t>::min(), 63);}, + "srl, negative"); + + // SRA + expect<int64_t>(255, []{return I::sra(65280, 8);}, "sra, general"); + expect<int64_t>(0, []{return I::sra(255, 8);}, "sra, erase"); + expect<int64_t>(-1, []{return I::sra(numeric_limits<int64_t>::min(), 63);}, + "sra, negative"); + + // OR + expect<uint64_t>(-1, + []{return I::or_inst(0xAAAAAAAAAAAAAAAAULL, + 0x5555555555555555ULL);}, + "or (1)"); + expect<uint64_t>(0xAAAAAAAAAAAAAAAAULL, + []{return I::or_inst(0xAAAAAAAAAAAAAAAAULL, + 0xAAAAAAAAAAAAAAAAULL);}, + "or (A)"); + + // AND + expect<uint64_t>(0, []{return I::and_inst(-1, 0);}, "and (0)"); + expect<uint64_t>(0x1234567812345678ULL, + []{return I::and_inst(0x1234567812345678ULL, -1);}, "and (-1)"); + + // FENCE/FENCE.I + asm volatile("fence" : : ); + asm volatile("fence.i" : : ); + + // ECALL + char fname[] = "test.txt"; + char teststr[] = "this is a test"; + expect<bool>(true, [=]{ + int fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fd < 0) { + return false; + } + size_t n = write(fd, teststr, sizeof(teststr)); + cout << "Bytes written: " << n << endl; + return close(fd) >= 0 && n > 0; + }, "open, write"); + expect<int>(0, [=]{return access(fname, F_OK);}, "access F_OK"); + expect<int>(0, [=]{return access(fname, R_OK);}, "access R_OK"); + expect<int>(0, [=]{return access(fname, W_OK);}, "access W_OK"); + // gem5's implementation of access is incorrect; it should return + // -1 on failure, not -errno. Account for this using an inequality. + expect<bool>(true, [=]{return access(fname, X_OK) != 0;}, "access X_OK"); + expect<bool>(true, [=]{ + struct stat stat_buf, fstat_buf; + int s = stat(fname, &stat_buf); + if (s < 0) { + return false; + } else { + cout << "stat:" << endl; + cout << "\tst_dev =\t" << stat_buf.st_dev << endl; + cout << "\tst_ino =\t" << stat_buf.st_ino << endl; + cout << "\tst_mode =\t" << stat_buf.st_mode << endl; + cout << "\tst_nlink =\t" << stat_buf.st_nlink << endl; + cout << "\tst_uid =\t" << stat_buf.st_uid << endl; + cout << "\tst_gid =\t" << stat_buf.st_gid << endl; + cout << "\tst_rdev =\t" << stat_buf.st_rdev << endl; + cout << "\tst_size =\t" << stat_buf.st_size << endl; + cout << "\tst_blksize =\t" << stat_buf.st_blksize << endl; + cout << "\tst_blocks =\t" << stat_buf.st_blocks << endl; + } + int fd = open(fname, O_RDONLY); + if (fd < 0) { + return false; + } + int f = fstat(fd, &fstat_buf); + if (f >= 0) { + cout << "fstat:" << endl; + cout << "\tst_dev =\t" << fstat_buf.st_dev << endl; + cout << "\tst_ino =\t" << fstat_buf.st_ino << endl; + cout << "\tst_mode =\t" << fstat_buf.st_mode << endl; + cout << "\tst_nlink =\t" << fstat_buf.st_nlink << endl; + cout << "\tst_uid =\t" << fstat_buf.st_uid << endl; + cout << "\tst_gid =\t" << fstat_buf.st_gid << endl; + cout << "\tst_rdev =\t" << fstat_buf.st_rdev << endl; + cout << "\tst_size =\t" << fstat_buf.st_size << endl; + cout << "\tst_blksize =\t" << fstat_buf.st_blksize << endl; + cout << "\tst_blocks =\t" << fstat_buf.st_blocks << endl; + } + return close(fd) >= 0 && f >= 0; + }, "open, stat"); + expect<bool>(true, [=]{ + int fd = open(fname, O_RDONLY); + if (fd < 0) { + return false; + } + char in[128]; + size_t n = read(fd, in, sizeof(in)); + cout << "Bytes read: " << n << endl; + cout << "String read: " << in << endl; + int cl = close(fd); + int un = unlink(fname); + return n > 0 && cl >= 0 && un >= 0 && strcmp(teststr, in) == 0; + }, "open, read, unlink"); + expect<bool>(true, []{ + struct tms buf; + clock_t t = times(&buf); + cout << "times:" << endl; + cout << "\ttms_utime =\t" << buf.tms_utime << endl; + cout << "\ttms_stime =\t" << buf.tms_stime << endl; + cout << "\ttms_cutime =\t" << buf.tms_cutime << endl; + cout << "\ttms_cstime =\t" << buf.tms_cstime << endl; + return t > 0; + }, "times"); + expect<int>(0, []{ + struct timeval time; + int res = gettimeofday(&time, nullptr); + cout << "timeval:" << endl; + cout << "\ttv_sec =\t" << time.tv_sec << endl; + cout << "\ttv_usec =\t" << time.tv_usec << endl; + return res; + }, "gettimeofday"); + + // EBREAK not tested because it only makes sense in FS mode or when + // using gdb + + // ERET not tested because it only makes sense in FS mode and will cause + // a panic when used in SE mode + + // CSRs (RDCYCLE, RDTIME, RDINSTRET) + expect<bool>(true, []{ + uint64_t cycles = 0; + asm("rdcycle %0" : "=r" (cycles)); + cout << "Cycles: " << cycles << endl; + return cycles > 0; + }, "rdcycle"); + expect<bool>(true, []{ + uint64_t time = 0; + asm("rdtime %0" : "=r" (time)); + cout << "Time: " << time << endl; + return time > 0; + }, "rdtime"); + expect<bool>(true, []{ + uint64_t instret = 0; + asm("rdinstret %0" : "=r" (instret)); + cout << "Instructions Retired: " << instret << endl; + return instret > 0; + }, "rdinstret"); + + // 64-bit memory (LWU, LD, SD) + expect<int64_t>(0xFFFFFFFF, []{return I::load<uint32_t, uint64_t>(-1);}, + "lwu"); + expect<int64_t>(30064771072, + []{return I::load<int64_t, int64_t>(30064771072);}, "ld"); + expect<uint64_t>(-1, []{return I::store<int64_t>(-1);}, "sd"); + + // ADDIW + expect<int64_t>(268435710, []{return I::addiw(0x0FFFFFFF, 255);}, "addiw"); + expect<int64_t>(-2147481602, []{return I::addiw(0x7FFFFFFF, 0x7FF);}, + "addiw, overflow"); + expect<int64_t>(0, []{return I::addiw(0x7FFFFFFFFFFFFFFFLL, 1);}, + "addiw, truncate"); + + // SLLIW + expect<int64_t>(65280, []{return I::slliw(255, 8);}, "slliw, general"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::slliw(255, 31);}, "slliw, erase"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::slliw(0xFFFFFFFF00800000LL, 8);}, "slliw, truncate"); + + // SRLIW + expect<int64_t>(255, []{return I::srliw(65280, 8);}, "srliw, general"); + expect<int64_t>(0, []{return I::srliw(255, 8);}, "srliw, erase"); + expect<int64_t>(1, + []{return I::srliw(numeric_limits<int32_t>::min(), 31);}, + "srliw, negative"); + expect<int64_t>(1, []{return I::srliw(0xFFFFFFFF80000000LL, 31);}, + "srliw, truncate"); + + // SRAIW + expect<int64_t>(255, []{return I::sraiw(65280, 8);}, "sraiw, general"); + expect<int64_t>(0, []{return I::sraiw(255, 8);}, "sraiw, erase"); + expect<int64_t>(-1, + []{return I::sraiw(numeric_limits<int32_t>::min(), 31);}, + "sraiw, negative"); + expect<int64_t>(-1, []{return I::sraiw(0x0000000180000000LL, 31);}, + "sraiw, truncate"); + + // ADDW + expect<int64_t>(1073742078, []{return I::addw(0x3FFFFFFF, 255);}, "addw"); + expect<int64_t>(-1, []{return I::addw(0x7FFFFFFF, 0x80000000);}, + "addw, overflow"); + expect<int64_t>(65536, []{return I::addw(0xFFFFFFFF0000FFFFLL, 1);}, + "addw, truncate"); + + // SUBW + expect<int64_t>(65535, []{return I::subw(65536, 1);}, "subw"); + expect<int64_t>(-1, []{return I::subw(0x7FFFFFFF, 0x80000000);}, + "subw, \"overflow\""); + expect<int64_t>(0, + []{return I::subw(0xAAAAAAAAFFFFFFFFULL, 0x55555555FFFFFFFFULL);}, + "subw, truncate"); + + // SLLW + expect<int64_t>(65280, []{return I::sllw(255, 8);}, "sllw, general"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::sllw(255, 31);}, "sllw, erase"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::sllw(0xFFFFFFFF00008000LL, 16);}, "sllw, truncate"); + + // SRLW + expect<uint64_t>(255, []{return I::srlw(65280, 8);}, "srlw, general"); + expect<uint64_t>(0, []{return I::srlw(255, 8);}, "srlw, erase"); + expect<uint64_t>(1, + []{return I::srlw(numeric_limits<int32_t>::min(), 31);}, + "srlw, negative"); + expect<uint64_t>(1, []{return I::srlw(0x0000000180000000LL, 31);}, + "srlw, truncate"); + + // SRAW + expect<int64_t>(255, []{return I::sraw(65280, 8);}, "sraw, general"); + expect<int64_t>(0, []{return I::sraw(255, 8);}, "sraw, erase"); + expect<int64_t>(-1, + []{return I::sraw(numeric_limits<int32_t>::min(), 31);}, + "sraw, negative"); + expect<int64_t>(1, []{return I::sraw(0xFFFFFFFF40000000LL, 30);}, + "sraw, truncate"); + + return 0; +} diff --git a/tests/test-progs/insttest/src/riscv/rv64i.h b/tests/test-progs/insttest/src/riscv/rv64i.h new file mode 100644 index 000000000..198fb367c --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/rv64i.h @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#pragma once + +#include <cstdint> +#include <iostream> + +#include "insttest.h" + +namespace I +{ + +inline uint64_t +lui(const uint32_t imm) +{ + int64_t rd = -1; + asm volatile("lui %0,%1" : "=r" (rd) : "i" (imm)); + return rd; +} + +inline bool +auipc(const uint64_t imm) +{ + int64_t rd = -1; + asm volatile("auipc %0,%1" : "=r" (rd) : "i" (imm)); + std::cout << "auipc: 0x" << std::hex << std::uppercase << rd << + std::nouppercase << std::dec << std::endl; + return rd >= imm; +} + +inline bool +jal() +{ + asm volatile goto("jal zero,%l[jallabel]" : : : : jallabel); + return false; + jallabel: + return true; +} + +inline bool +jalr() +{ + int a = 0; + asm volatile("auipc %0,0;" + "jalr t0,%0,12;" + "addi %0,zero,0;" + "sub %0,t0,%0;" + : "+r" (a) + : + : "t0"); + return a == 8; +} + +inline bool +beq(int64_t a, int64_t b) +{ + asm volatile goto("beq %0,%1,%l[beqlabel]" + : + : "r" (a), "r" (b) + : + : beqlabel); + return false; + beqlabel: + return true; +} + +inline bool +bne(int64_t a, int64_t b) +{ + asm volatile goto("bne %0,%1,%l[bnelabel]" + : + : "r" (a), "r" (b) + : + : bnelabel); + return false; + bnelabel: + return true; +} + +inline bool +blt(int64_t a, int64_t b) +{ + asm volatile goto("blt %0,%1,%l[bltlabel]" + : + : "r" (a), "r" (b) + : + : bltlabel); + return false; + bltlabel: + return true; +} + +inline bool +bge(int64_t a, int64_t b) +{ + asm volatile goto("bge %0,%1,%l[bgelabel]" + : + : "r" (a), "r" (b) + : + : bgelabel); + return false; + bgelabel: + return true; +} + +inline bool +bltu(uint64_t a, uint64_t b) +{ + asm volatile goto("bltu %0,%1,%l[bltulabel]" + : + : "r" (a), "r" (b) + : + : bltulabel); + return false; + bltulabel: + return true; +} + +inline bool +bgeu(uint64_t a, uint64_t b) +{ + asm volatile goto("bgeu %0,%1,%l[bgeulabel]" + : + : "r" (a), "r" (b) + : + : bgeulabel); + return false; + bgeulabel: + return true; +} + +template<typename M, typename R> inline R +load(const M& b) +{ + R a = 0; + switch(sizeof(M)) + { + case 1: + if (std::is_signed<M>::value) { + asm volatile("lb %0,%1" : "=r" (a) : "m" (b)); + } else { + asm volatile("lbu %0,%1" : "=r" (a) : "m" (b)); + } + break; + case 2: + if (std::is_signed<M>::value) { + asm volatile("lh %0,%1" : "=r" (a) : "m" (b)); + } else { + asm volatile("lhu %0,%1" : "=r" (a) : "m" (b)); + } + break; + case 4: + if (std::is_signed<M>::value) { + asm volatile("lw %0,%1" : "=r" (a) : "m" (b)); + } else { + asm volatile("lwu %0,%1" : "=r" (a) : "m" (b)); + } + break; + case 8: + asm volatile("ld %0,%1" : "=r" (a) : "m" (b)); + break; + } + return a; +} + +template<typename M> inline M +store(const M& rs2) +{ + M mem = 0; + switch (sizeof(M)) + { + case 1: + asm volatile("sb %1,%0" : "=m" (mem) : "r" (rs2)); + break; + case 2: + asm volatile("sh %1,%0" : "=m" (mem) : "r" (rs2)); + break; + case 4: + asm volatile("sw %1,%0" : "=m" (mem) : "r" (rs2)); + break; + case 8: + asm volatile("sd %1,%0" : "=m" (mem) : "r" (rs2)); + break; + } + return mem; +} + +inline int64_t +addi(int64_t rs1, const int16_t imm) +{ + int64_t rd = 0; + IOP("addi", rd, rs1, imm); + return rd; +} + +inline bool +slti(int64_t rs1, const int16_t imm) +{ + bool rd = false; + IOP("slti", rd, rs1, imm); + return rd; +} + +inline bool +sltiu(uint64_t rs1, const uint16_t imm) +{ + bool rd = false; + IOP("sltiu", rd, rs1, imm); + return rd; +} + +inline uint64_t +xori(uint64_t rs1, const uint16_t imm) +{ + uint64_t rd = 0; + IOP("xori", rd, rs1, imm); + return rd; +} + +inline uint64_t +ori(uint64_t rs1, const uint16_t imm) +{ + uint64_t rd = 0; + IOP("ori", rd, rs1, imm); + return rd; +} + +inline uint64_t +andi(uint64_t rs1, const uint16_t imm) +{ + uint64_t rd = 0; + IOP("andi", rd, rs1, imm); + return rd; +} + +inline int64_t +slli(int64_t rs1, const uint16_t imm) +{ + int64_t rd = 0; + IOP("slli", rd, rs1, imm); + return rd; +} + +inline uint64_t +srli(uint64_t rs1, const uint16_t imm) +{ + uint64_t rd = 0; + IOP("srli", rd, rs1, imm); + return rd; +} + +inline int64_t +srai(int64_t rs1, const uint16_t imm) +{ + int64_t rd = 0; + IOP("srai", rd, rs1, imm); + return rd; +} + +inline int64_t +add(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("add", rd, rs1, rs2); + return rd; +} + +inline int64_t +sub(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("sub", rd, rs1, rs2); + return rd; +} + +inline int64_t +sll(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("sll", rd, rs1, rs2); + return rd; +} + +inline bool +slt(int64_t rs1, int64_t rs2) +{ + bool rd = false; + ROP("slt", rd, rs1, rs2); + return rd; +} + +inline bool +sltu(uint64_t rs1, uint64_t rs2) +{ + bool rd = false; + ROP("sltu", rd, rs1, rs2); + return rd; +} + +inline uint64_t +xor_inst(uint64_t rs1, uint64_t rs2) +{ + uint64_t rd = 0; + ROP("xor", rd, rs1, rs2); + return rd; +} + +inline uint64_t +srl(uint64_t rs1, uint64_t rs2) +{ + uint64_t rd = 0; + ROP("srl", rd, rs1, rs2); + return rd; +} + +inline int64_t +sra(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("sra", rd, rs1, rs2); + return rd; +} + +inline uint64_t +or_inst(uint64_t rs1, uint64_t rs2) +{ + uint64_t rd = 0; + ROP("or", rd, rs1, rs2); + return rd; +} + +inline uint64_t +and_inst(uint64_t rs1, uint64_t rs2) +{ + uint64_t rd = 0; + ROP("and", rd, rs1, rs2); + return rd; +} + +inline int64_t +addiw(int64_t rs1, const int16_t imm) +{ + int64_t rd = 0; + IOP("addiw", rd, rs1, imm); + return rd; +} + +inline int64_t +slliw(int64_t rs1, const uint16_t imm) +{ + int64_t rd = 0; + IOP("slliw", rd, rs1, imm); + return rd; +} + +inline uint64_t +srliw(uint64_t rs1, const uint16_t imm) +{ + uint64_t rd = 0; + IOP("srliw", rd, rs1, imm); + return rd; +} + +inline int64_t +sraiw(int64_t rs1, const uint16_t imm) +{ + int64_t rd = 0; + IOP("sraiw", rd, rs1, imm); + return rd; +} + +inline int64_t +addw(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("addw", rd, rs1, rs2); + return rd; +} + +inline int64_t +subw(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("subw", rd, rs1, rs2); + return rd; +} + +inline int64_t +sllw(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("sllw", rd, rs1, rs2); + return rd; +} + +inline uint64_t +srlw(uint64_t rs1, uint64_t rs2) +{ + uint64_t rd = 0; + ROP("srlw", rd, rs1, rs2); + return rd; +} + +inline int64_t +sraw(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("sraw", rd, rs1, rs2); + return rd; +} + +} // namespace I diff --git a/tests/test-progs/insttest/src/riscv/rv64m.cpp b/tests/test-progs/insttest/src/riscv/rv64m.cpp new file mode 100644 index 000000000..836d771a1 --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/rv64m.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#include <cstdint> +#include <limits> + +#include "insttest.h" +#include "rv64m.h" + +int main() +{ + using namespace std; + using namespace insttest; + + // MUL + expect<int64_t>(39285, []{return M::mul(873, 45);}, "mul"); + expect<int64_t>(0, []{return M::mul(0x4000000000000000LL, 4);}, + "mul, overflow"); + + // MULH + expect<int64_t>(1, []{return M::mulh(0x4000000000000000LL, 4);}, "mulh"); + expect<int64_t>(-1, []{return M::mulh(numeric_limits<int64_t>::min(), 2);}, + "mulh, negative"); + expect<int64_t>(0, []{return M::mulh(-1, -1);}, "mulh, all bits set"); + + // MULHSU + expect<int64_t>(-1, []{return M::mulhsu(-1, -1);}, "mulhsu, all bits set"); + expect<int64_t>(-1, + []{return M::mulhsu(numeric_limits<int64_t>::min(), 2);},\ + "mulhsu"); + + // MULHU + expect<uint64_t>(1, []{return M::mulhu(0x8000000000000000ULL, 2);}, + "mulhu"); + expect<uint64_t>(0xFFFFFFFFFFFFFFFEULL, []{return M::mulhu(-1, -1);}, + "mulhu, all bits set"); + + // DIV + expect<int64_t>(-7, []{return M::div(-59, 8);}, "div"); + expect<int64_t>(-1, []{return M::div(255, 0);}, "div/0"); + expect<int64_t>(numeric_limits<int64_t>::min(), + []{return M::div(numeric_limits<int64_t>::min(), -1);}, + "div, overflow"); + + // DIVU + expect<uint64_t>(2305843009213693944LL, []{return M::divu(-59, 8);}, + "divu"); + expect<uint64_t>(numeric_limits<uint64_t>::max(), + []{return M::divu(255, 0);}, "divu/0"); + expect<uint64_t>(0, + []{return M::divu(numeric_limits<uint64_t>::min(), -1);}, + "divu, \"overflow\""); + + // REM + expect<int64_t>(-3, []{return M::rem(-59, 8);}, "rem"); + expect<int64_t>(255, []{return M::rem(255, 0);}, "rem/0"); + expect<int64_t>(0, []{return M::rem(numeric_limits<int64_t>::min(), -1);}, + "rem, overflow"); + + // REMU + expect<uint64_t>(5, []{return M::remu(-59, 8);}, "remu"); + expect<uint64_t>(255, []{return M::remu(255, 0);}, "remu/0"); + expect<uint64_t>(0x8000000000000000ULL, + []{return M::remu(0x8000000000000000ULL, -1);}, + "remu, \"overflow\""); + + // MULW + expect<int64_t>(-100, + []{return M::mulw(0x7FFFFFFF00000005LL, 0x80000000FFFFFFECLL);}, + "mulw, truncate"); + expect<int64_t>(0, []{return M::mulw(0x40000000, 4);}, "mulw, overflow"); + + // DIVW + expect<int64_t>(-7, + []{return M::divw(0x7FFFFFFFFFFFFFC5LL, 0xFFFFFFFF00000008LL);}, + "divw, truncate"); + expect<int64_t>(-1, []{return M::divw(65535, 0);}, "divw/0"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return M::divw(numeric_limits<int32_t>::min(), -1);}, + "divw, overflow"); + + // DIVUW + expect<int64_t>(536870904, + []{return M::divuw(0x7FFFFFFFFFFFFFC5LL, 0xFFFFFFFF00000008LL);}, + "divuw, truncate"); + expect<int64_t>(numeric_limits<uint64_t>::max(), + []{return M::divuw(65535, 0);}, "divuw/0"); + expect<int64_t>(0, + []{return M::divuw(numeric_limits<int32_t>::min(), -1);}, + "divuw, \"overflow\""); + expect<int64_t>(-1, + []{return M::divuw(numeric_limits<uint32_t>::max(), 1);}, + "divuw, sign extend"); + + // REMW + expect<int64_t>(-3, + []{return M::remw(0x7FFFFFFFFFFFFFC5LL, 0xFFFFFFFF00000008LL);}, + "remw, truncate"); + expect<int64_t>(65535, []{return M::remw(65535, 0);}, "remw/0"); + expect<int64_t>(0, []{return M::remw(numeric_limits<int32_t>::min(), -1);}, + "remw, overflow"); + + // REMUW + expect<int64_t>(5, + []{return M::remuw(0x7FFFFFFFFFFFFFC5LL, 0xFFFFFFFF00000008LL);}, + "remuw, truncate"); + expect<int64_t>(65535, []{return M::remuw(65535, 0);}, "remuw/0"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return M::remuw(numeric_limits<int32_t>::min(), -1);}, + "remuw, \"overflow\""); + expect<int64_t>(0xFFFFFFFF80000000, + []{return M::remuw(0x80000000, 0xFFFFFFFF);}, + "remuw, sign extend"); + + return 0; +} diff --git a/tests/test-progs/insttest/src/riscv/rv64m.h b/tests/test-progs/insttest/src/riscv/rv64m.h new file mode 100644 index 000000000..b93a7d623 --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/rv64m.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#pragma once + +#include <cstdint> + +#include "insttest.h" + +namespace M +{ + +inline int64_t +mul(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("mul", rd, rs1, rs2); + return rd; +} + +inline int64_t +mulh(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("mulh", rd, rs1, rs2); + return rd; +} + +inline int64_t +mulhsu(int64_t rs1, uint64_t rs2) +{ + int64_t rd = 0; + ROP("mulhsu", rd, rs1, rs2); + return rd; +} + +inline uint64_t +mulhu(uint64_t rs1, uint64_t rs2) +{ + uint64_t rd = 0; + ROP("mulhu", rd, rs1, rs2); + return rd; +} + +inline int64_t +div(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("div", rd, rs1, rs2); + return rd; +} + +inline uint64_t +divu(uint64_t rs1, uint64_t rs2) +{ + uint64_t rd = 0; + ROP("divu", rd, rs1, rs2); + return rd; +} + +inline int64_t +rem(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("rem", rd, rs1, rs2); + return rd; +} + +inline uint64_t +remu(uint64_t rs1, uint64_t rs2) +{ + uint64_t rd = 0; + ROP("remu", rd, rs1, rs2); + return rd; +} + +inline int64_t +mulw(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("mulw", rd, rs1, rs2); + return rd; +} + +inline int64_t +divw(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("divw", rd, rs1, rs2); + return rd; +} + +inline uint64_t +divuw(uint64_t rs1, uint64_t rs2) +{ + uint64_t rd = 0; + ROP("divuw", rd, rs1, rs2); + return rd; +} + +inline int64_t +remw(int64_t rs1, int64_t rs2) +{ + int64_t rd = 0; + ROP("remw", rd, rs1, rs2); + return rd; +} + +inline uint64_t +remuw(uint64_t rs1, uint64_t rs2) +{ + uint64_t rd = 0; + ROP("remuw", rd, rs1, rs2); + return rd; +} + +} // namespace M |