33683bd087
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>
433 lines
18 KiB
C++
433 lines
18 KiB
C++
/*
|
|
* 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;
|
|
}
|