Skip to content

Commit

Permalink
feat: Validate even-odd register requirements of machine instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
slavek-kucera authored Apr 30, 2024
1 parent 2a52672 commit 6575b89
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 89 deletions.
3 changes: 3 additions & 0 deletions clients/vscode-hlasmplugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## ****Unreleased****

#### Added
- Validate even-odd register requirements of machine instructions

## [1.13.0](https://github.com/eclipse-che4z/che-che4z-lsp-for-hlasm/compare/1.12.0...1.13.0) (2024-04-24)

#### Added
Expand Down
25 changes: 23 additions & 2 deletions parser_library/src/checking/instr_operand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ bool machine_operand::is_size_corresponding_unsigned(int operand, int size)
return operand >= 0 && operand <= (1ll << size) - 1;
}

namespace {
bool check_value_parity(int operand, even_odd_register reg)
{
switch (reg)
{
case even_odd_register::NONE:
return true;
case even_odd_register::ODD:
return !!(operand & 1);
case even_odd_register::EVEN:
return !(operand & 1);
}
}
} // namespace

bool machine_operand::is_simple_operand(const machine_operand_format& operand)
{
return (operand.first.is_signed == false && operand.first.size == 0 && operand.second.is_signed == false
Expand Down Expand Up @@ -303,13 +318,19 @@ bool one_operand::check(
}
return false;
}
if (!to_check.identifier.is_signed && !is_size_corresponding_unsigned(value, to_check.identifier.size))
if (!to_check.identifier.is_signed
&& (!is_size_corresponding_unsigned(value, to_check.identifier.size)
|| !check_value_parity(value, to_check.identifier.evenodd) || value < to_check.identifier.min_register))
{
auto boundary = (1ll << to_check.identifier.size) - 1;
static constexpr std::string_view reg_qual[] = { "", "odd", "even" };
switch (to_check.identifier.type)
{
case machine_operand_type::REG:
diag = diagnostic_op::error_M120(instr_name, operand_range);
diag = diagnostic_op::error_M120(instr_name,
operand_range,
reg_qual[(int)to_check.identifier.evenodd],
to_check.identifier.min_register);
break;
case machine_operand_type::MASK:
diag = diagnostic_op::error_M121(instr_name, operand_range);
Expand Down
19 changes: 14 additions & 5 deletions parser_library/src/checking/instr_operand.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,26 @@ enum class machine_operand_type : uint8_t
RELOC_IMM,
};

enum class even_odd_register : uint8_t
{
NONE,
ODD,
EVEN,
};

// Describes a component of machine operand format. Specifies allowed values.
struct parameter
{
bool is_signed;
uint8_t size;
machine_operand_type type;

constexpr bool is_empty() const { return (!is_signed && type == machine_operand_type::NONE && size == 0); }
bool is_signed : 1;
uint8_t size : 7;
machine_operand_type type : 4;
even_odd_register evenodd : 2 = even_odd_register::NONE;
uint8_t min_register : 2 = 0;

bool operator==(const parameter&) const = default;

constexpr bool is_empty() const { return *this == parameter {}; }

std::string to_string() const;
};

Expand Down
20 changes: 20 additions & 0 deletions parser_library/src/context/instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,21 @@ enum class mach_format : unsigned char

constexpr checking::parameter empty = { false, 0, checking::machine_operand_type::NONE };
constexpr checking::parameter reg = { false, 4, checking::machine_operand_type::REG };
constexpr checking::parameter reg_nz = {
false, 4, checking::machine_operand_type::REG, checking::even_odd_register::NONE, 1
};
constexpr checking::parameter reg_2 = {
false, 4, checking::machine_operand_type::REG, checking::even_odd_register::NONE, 2
};
constexpr checking::parameter reg_odd = {
false, 4, checking::machine_operand_type::REG, checking::even_odd_register::ODD
};
constexpr checking::parameter reg_even = {
false, 4, checking::machine_operand_type::REG, checking::even_odd_register::EVEN
};
constexpr checking::parameter reg_even_nz = {
false, 4, checking::machine_operand_type::REG, checking::even_odd_register::EVEN, 2
};
constexpr checking::parameter dis_reg = { false, 4, checking::machine_operand_type::DIS_REG };
constexpr checking::parameter dis_reg_r = { false, 4, checking::machine_operand_type::REG };
constexpr checking::parameter mask = { false, 4, checking::machine_operand_type::MASK };
Expand Down Expand Up @@ -247,6 +262,11 @@ constexpr checking::machine_operand_format dxb_12_4x4_U(dis_12u, dis_reg, base_)
constexpr checking::machine_operand_format dxb_20_4x4_S(dis_20s, dis_reg, base_);
constexpr checking::machine_operand_format dvb_12_5x4_U(dis_12u, vec_reg, base_);
constexpr checking::machine_operand_format reg_4_U(reg, empty, empty);
constexpr checking::machine_operand_format reg_4_U_nz(reg_nz, empty, empty);
constexpr checking::machine_operand_format reg_4_U_2(reg_2, empty, empty);
constexpr checking::machine_operand_format reg_4_U_odd(reg_odd, empty, empty);
constexpr checking::machine_operand_format reg_4_U_even(reg_even, empty, empty);
constexpr checking::machine_operand_format reg_4_U_even_nz(reg_even_nz, empty, empty);
constexpr checking::machine_operand_format mask_4_U(mask, empty, empty);
constexpr checking::machine_operand_format imm_4_U(imm_4u, empty, empty);
constexpr checking::machine_operand_format imm_8_S(imm_8s, empty, empty);
Expand Down
Loading

0 comments on commit 6575b89

Please sign in to comment.