Skip to content

Commit

Permalink
i#3544: RV64: Split PC-sensitive IR tests into another test (#7102)
Browse files Browse the repository at this point in the history
Disassemble result of instructions like jal and auipc on riscv64 is
PC-sensitve, i.e. depends on the current PC value. We used to omit the
check since address of the buffer that we encode instructions to is
unknown before running the test.

This commit splits IR tests of these instructions out and enables regex
match to handle the varying addresses. It's important to keep it small
and standalone to workaround the inefficient regex implementation of
CMake.

Issue: #3544
  • Loading branch information
ziyao233 authored Dec 8, 2024
1 parent 500483e commit e84dcdb
Show file tree
Hide file tree
Showing 7 changed files with 339 additions and 173 deletions.
7 changes: 7 additions & 0 deletions suite/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2054,6 +2054,10 @@ if (NOT ANDROID)

if (RISCV64)
tobuild_api(api.ir_rvv api/ir_rvv.c "" "" ON OFF OFF)
tobuild_api(api.ir_rv64_addr api/ir_rv64_addr.c "" "" OFF OFF OFF)

target_sources(api.ir PRIVATE api/ir_riscv64_common.c)
target_sources(api.ir_rv64_addr PRIVATE api/ir_riscv64_common.c)
endif(RISCV64)
endif ()

Expand All @@ -2067,6 +2071,8 @@ if (AARCH64)
set(api.ir-static_runcmp "${CMAKE_CURRENT_SOURCE_DIR}/runcmp.cmake")
set(api.ir-static_runcmp_capture "stderr")
elseif (RISCV64)
target_sources(api.ir-static PRIVATE api/ir_riscv64_common.c)

# The ir_riscv64.expect file is too large for CMake's regexes.
set(api.ir-static_runcmp "${CMAKE_CURRENT_SOURCE_DIR}/runcmp.cmake")
set(api.ir-static_runcmp_capture "stderr")
Expand Down Expand Up @@ -6419,6 +6425,7 @@ if (RISCV64)
code_api|api.ir-static
code_api|api.ir_regdeps
code_api|api.ir_rvv
code_api|api.ir_rv64_addr
code_api|client.app_args
code_api|client.blackbox
code_api|client.crashmsg
Expand Down
176 changes: 4 additions & 172 deletions suite/tests/api/ir_riscv64.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,116 +48,7 @@
#include "dr_ir_utils.h"
#include "dr_defines.h"

static byte buf[8192];

#ifdef STANDALONE_DECODER
# define ASSERT(x) \
((void)((!(x)) ? (fprintf(stderr, "ASSERT FAILURE (standalone): %s:%d: %s\n", \
__FILE__, __LINE__, #x), \
abort(), 0) \
: 0))
#else
# define ASSERT(x) \
((void)((!(x)) ? (dr_fprintf(STDERR, "ASSERT FAILURE (client): %s:%d: %s\n", \
__FILE__, __LINE__, #x), \
dr_abort(), 0) \
: 0))
#endif

static byte *
test_instr_encoding(void *dc, uint opcode, instr_t *instr)
{
instr_t *decin;
byte *pc, *next_pc;

ASSERT(instr_get_opcode(instr) == opcode);
instr_disassemble(dc, instr, STDERR);
print("\n");
ASSERT(instr_is_encoding_possible(instr));
pc = instr_encode(dc, instr, buf);
ASSERT(pc != NULL);
decin = instr_create(dc);
next_pc = decode(dc, buf, decin);
ASSERT(next_pc != NULL);
if (!instr_same(instr, decin)) {
print("Disassembled as:\n");
instr_disassemble(dc, decin, STDERR);
print("\n");
ASSERT(instr_same(instr, decin));
}

instr_destroy(dc, instr);
instr_destroy(dc, decin);
return pc;
}

static void
test_instr_encoding_failure(void *dc, uint opcode, app_pc instr_pc, instr_t *instr)
{
byte *pc;

pc = instr_encode_to_copy(dc, instr, buf, instr_pc);
ASSERT(pc == NULL);
instr_destroy(dc, instr);
}

static byte *
test_instr_decoding_failure(void *dc, uint raw_instr)
{
instr_t *decin;
byte *pc;

*(uint *)buf = raw_instr;
decin = instr_create(dc);
pc = decode(dc, buf, decin);
/* Returns NULL on failure. */
ASSERT(pc == NULL);
instr_destroy(dc, decin);
return pc;
}

static void
test_instr_encoding_jal_or_branch(void *dc, uint opcode, instr_t *instr)
{
/* XXX i#3544: For jal and branch instructions, current disassembler will print
* the complete jump address, that is, an address relative to `buf`. But the
* value of `buf` is indeterminate at runtime, so we skip checking the disassembled
* format for these instructions. Same for test_instr_encoding_auipc().
*
* FIXME i#3544: For branch instructions, we should use relative offsets instead.
*/
instr_t *decin;
byte *pc, *next_pc;

ASSERT(instr_get_opcode(instr) == opcode);
ASSERT(instr_is_encoding_possible(instr));
pc = instr_encode(dc, instr, buf);
ASSERT(pc != NULL);
decin = instr_create(dc);
next_pc = decode(dc, buf, decin);
ASSERT(next_pc != NULL);
ASSERT(instr_same(instr, decin));
instr_destroy(dc, instr);
instr_destroy(dc, decin);
}

static void
test_instr_encoding_auipc(void *dc, uint opcode, app_pc instr_pc, instr_t *instr)
{
instr_t *decin;
byte *pc, *next_pc;

ASSERT(instr_get_opcode(instr) == opcode);
ASSERT(instr_is_encoding_possible(instr));
pc = instr_encode_to_copy(dc, instr, buf, instr_pc);
ASSERT(pc != NULL);
decin = instr_create(dc);
next_pc = decode_from_copy(dc, buf, instr_pc, decin);
ASSERT(next_pc != NULL);
ASSERT(instr_same(instr, decin));
instr_destroy(dc, instr);
instr_destroy(dc, decin);
}
#include "ir_riscv64.h"

static void
test_integer_load_store(void *dc)
Expand Down Expand Up @@ -1068,59 +959,17 @@ test_jump_and_branch(void *dc)
opnd_create_immed_int(42, OPSZ_20b));
pc = test_instr_encoding(dc, OP_lui, instr);

/* Not printing disassembly for jal and branch instructions below, see comment of
* test_instr_encoding_jal_or_branch(). */
instr = INSTR_CREATE_auipc(dc, opnd_create_reg(DR_REG_A0),
OPND_CREATE_ABSMEM(pc + (3 << 12), OPSZ_0));
test_instr_encoding_auipc(dc, OP_auipc, pc, instr);

instr = INSTR_CREATE_auipc(dc, opnd_create_reg(DR_REG_A0),
OPND_CREATE_ABSMEM(pc + (3 << 12), OPSZ_0));
test_instr_encoding_auipc(dc, OP_auipc, pc, instr);

instr = INSTR_CREATE_auipc(dc, opnd_create_reg(DR_REG_A0),
OPND_CREATE_ABSMEM(pc + (3 << 12), OPSZ_0));
/* This is expected to fail since we are using an unaligned PC (i.e. target_pc -
* instr_encode_pc has non-zero lower 12 bits). */
test_instr_encoding_failure(dc, OP_auipc, pc + 4, instr);

instr = INSTR_CREATE_jal(dc, opnd_create_reg(DR_REG_A0), opnd_create_pc(pc));
test_instr_encoding_jal_or_branch(dc, OP_jal, instr);
instr = INSTR_CREATE_jalr(dc, opnd_create_reg(DR_REG_A0), opnd_create_reg(DR_REG_A1),
opnd_create_immed_int(42, OPSZ_12b));
test_instr_encoding(dc, OP_jalr, instr);

instr = INSTR_CREATE_beq(dc, opnd_create_pc(pc), opnd_create_reg(DR_REG_A0),
opnd_create_reg(DR_REG_A1));
test_instr_encoding_jal_or_branch(dc, OP_beq, instr);
instr = INSTR_CREATE_bne(dc, opnd_create_pc(pc), opnd_create_reg(DR_REG_A0),
opnd_create_reg(DR_REG_A1));
test_instr_encoding_jal_or_branch(dc, OP_bne, instr);
instr = INSTR_CREATE_blt(dc, opnd_create_pc(pc), opnd_create_reg(DR_REG_A0),
opnd_create_reg(DR_REG_A1));
test_instr_encoding_jal_or_branch(dc, OP_blt, instr);
instr = INSTR_CREATE_bge(dc, opnd_create_pc(pc), opnd_create_reg(DR_REG_A0),
opnd_create_reg(DR_REG_A1));
test_instr_encoding_jal_or_branch(dc, OP_bge, instr);
instr = INSTR_CREATE_bltu(dc, opnd_create_pc(pc), opnd_create_reg(DR_REG_A0),
opnd_create_reg(DR_REG_A1));
test_instr_encoding_jal_or_branch(dc, OP_bltu, instr);
instr = INSTR_CREATE_bgeu(dc, opnd_create_pc(pc), opnd_create_reg(DR_REG_A0),
opnd_create_reg(DR_REG_A1));
test_instr_encoding_jal_or_branch(dc, OP_bgeu, instr);

/* Compressed */
instr = INSTR_CREATE_c_j(dc, opnd_create_pc(pc));
test_instr_encoding_jal_or_branch(dc, OP_c_j, instr);
instr = INSTR_CREATE_c_jr(dc, opnd_create_reg(DR_REG_A0));
test_instr_encoding_jal_or_branch(dc, OP_c_jr, instr);
/* There is no c.jal in RV64. */
test_instr_encoding(dc, OP_c_jr, instr);

instr = INSTR_CREATE_c_jalr(dc, opnd_create_reg(DR_REG_A0));
test_instr_encoding(dc, OP_c_jalr, instr);
instr = INSTR_CREATE_c_beqz(dc, opnd_create_pc(pc), opnd_create_reg(DR_REG_X8));
test_instr_encoding_jal_or_branch(dc, OP_c_beqz, instr);
instr = INSTR_CREATE_c_bnez(dc, opnd_create_pc(pc), opnd_create_reg(DR_REG_X8));
test_instr_encoding_jal_or_branch(dc, OP_c_bnez, instr);

instr = INSTR_CREATE_c_li(dc, opnd_create_reg(DR_REG_A1),
opnd_create_immed_int((1 << 5) - 1, OPSZ_5b));
test_instr_encoding(dc, OP_c_li, instr);
Expand Down Expand Up @@ -1442,23 +1291,6 @@ test_xinst(void *dc)
opnd_get_immed_int(instr_get_src(instr, 1)) == 0);
test_instr_encoding(dc, OP_jalr, instr);

/* Not printing disassembly for jal and branch instructions below, see comment of
* test_instr_encoding_jal_or_branch(). */
instr = XINST_CREATE_jump(dc, opnd_create_pc(pc));
ASSERT(opnd_is_reg(instr_get_dst(instr, 0)) &&
opnd_get_reg(instr_get_dst(instr, 0)) == DR_REG_ZERO);
test_instr_encoding_jal_or_branch(dc, OP_jal, instr);

instr = XINST_CREATE_jump_short(dc, opnd_create_pc(pc));
ASSERT(opnd_is_reg(instr_get_dst(instr, 0)) &&
opnd_get_reg(instr_get_dst(instr, 0)) == DR_REG_ZERO);
test_instr_encoding_jal_or_branch(dc, OP_jal, instr);

instr = XINST_CREATE_call(dc, opnd_create_pc(pc));
ASSERT(opnd_is_reg(instr_get_dst(instr, 0)) &&
opnd_get_reg(instr_get_dst(instr, 0)) == DR_REG_RA);
test_instr_encoding_jal_or_branch(dc, OP_jal, instr);

instr = XINST_CREATE_add(dc, opnd_create_reg(DR_REG_A0), opnd_create_reg(DR_REG_A1));
ASSERT(opnd_is_reg(instr_get_dst(instr, 0)) &&
opnd_get_reg(instr_get_dst(instr, 0)) == DR_REG_A0);
Expand Down
2 changes: 1 addition & 1 deletion suite/tests/api/ir_riscv64.expect
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,8 @@ c.xor fp a5 -> fp
c.sub fp a5 -> fp
test_integer_arith complete
lui 0x2a -> a0
<Internal Error: Failed to encode instruction: 'auipc <rel> 0x000055555556f014 -> a0'>
jalr a1 42 -> a0
c.jr a0 0 -> zero
c.jalr a0 0 -> ra
c.li zero 31 -> a1
c.lui 0x1 -> a1
Expand Down
68 changes: 68 additions & 0 deletions suite/tests/api/ir_riscv64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* **********************************************************
* Copyright (c) 2024 Institute of Software Chinese Academy of Sciences (ISCAS).
* 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 ISCAS 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 ISCAS 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.
*/

#ifndef IR_RISCV64_H
#define IR_RISCV64_H

#include "configure.h"
#include "dr_api.h"
#include "tools.h"
#include "dr_ir_utils.h"
#include "dr_defines.h"

#ifdef STANDALONE_DECODER
# define ASSERT(x) \
((void)((!(x)) ? (fprintf(stderr, "ASSERT FAILURE (standalone): %s:%d: %s\n", \
__FILE__, __LINE__, #x), \
abort(), 0) \
: 0))
#else
# define ASSERT(x) \
((void)((!(x)) ? (dr_fprintf(STDERR, "ASSERT FAILURE (client): %s:%d: %s\n", \
__FILE__, __LINE__, #x), \
dr_abort(), 0) \
: 0))
#endif

extern byte buf[8192];

byte *
test_instr_encoding_copy(void *dc, uint opcode, app_pc instr_pc, instr_t *instr);
byte *
test_instr_encoding(void *dc, uint opcode, instr_t *instr);
void
test_instr_encoding_failure(void *dc, uint opcode, app_pc instr_pc, instr_t *instr);
byte *
test_instr_decoding_failure(void *dc, uint raw_instr);

#endif /* IR_RISCV64_H */
Loading

0 comments on commit e84dcdb

Please sign in to comment.