Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Literal support #207

Merged
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
10b5e5c
prep for richer mach attributes
slavek-kucera Nov 9, 2021
6f14d54
fix reference to nullptr
slavek-kucera Nov 11, 2021
78d1e36
specialize is_similar for std pointer-like objects
slavek-kucera Nov 11, 2021
7bb8eec
...
slavek-kucera Nov 12, 2021
c7c6c65
fix: Current location counter changes between individual DC/DS operands
slavek-kucera Nov 12, 2021
dd42bc0
literals (WIP)
slavek-kucera Nov 12, 2021
afb7251
stateless loctr expressions
slavek-kucera Nov 16, 2021
533147b
Final all the things
slavek-kucera Nov 16, 2021
4fd0551
WIP
slavek-kucera Nov 16, 2021
c05fcd2
remove confusing alias
slavek-kucera Nov 18, 2021
8664ac2
adjust literal collection
slavek-kucera Nov 18, 2021
9124c60
refactoring of dependency evaluation context
slavek-kucera Nov 18, 2021
5034466
order pending literal pool elements
slavek-kucera Nov 18, 2021
3196a50
...
slavek-kucera Nov 19, 2021
f02f223
refactor data definition visitor
slavek-kucera Nov 19, 2021
941bee6
test for occurences in literals and location counter detection
slavek-kucera Nov 19, 2021
94b7087
a few literal tests
slavek-kucera Nov 19, 2021
90334f6
cleanup
slavek-kucera Nov 19, 2021
22535a1
no nested literals
slavek-kucera Nov 22, 2021
8c71440
test for nested literals
slavek-kucera Nov 22, 2021
cfa3d11
wip - issue with adding literal alias while generating pool
slavek-kucera Nov 22, 2021
ad993f3
refactor dep solver
slavek-kucera Nov 22, 2021
60b1a38
cleanup messages
slavek-kucera Nov 23, 2021
3e53164
fix duplicate literal handling
slavek-kucera Nov 23, 2021
b5912cb
support literals in mach_expr_data_attr
slavek-kucera Nov 23, 2021
9e8c188
attribute support for literals in machine expressions
slavek-kucera Nov 23, 2021
d0ff28f
WIP - ca sets not working
slavek-kucera Nov 23, 2021
3b2b3fb
basic support for literal attributes in ca statements
slavek-kucera Nov 24, 2021
1d4f750
fix missing literal registration
slavek-kucera Nov 24, 2021
aff24e1
fixes
slavek-kucera Nov 24, 2021
9d8186d
implement LTORG
slavek-kucera Nov 24, 2021
39414dd
fixes
slavek-kucera Nov 25, 2021
59ce91b
enhance is_similar
slavek-kucera Nov 25, 2021
5208786
implement literal comparison
slavek-kucera Nov 25, 2021
0b91259
test for similar literals
slavek-kucera Nov 25, 2021
022c67f
unconditionally examine all operands
slavek-kucera Nov 25, 2021
78fd035
incomplete fix for CR LF in strings
slavek-kucera Nov 25, 2021
92dca17
CA self def term support
slavek-kucera Nov 26, 2021
93b4eda
test for literal occurence in CA context
slavek-kucera Nov 26, 2021
182a0f0
...
slavek-kucera Nov 26, 2021
d2980b2
code smells
slavek-kucera Nov 26, 2021
7d17d4e
keep literal range
slavek-kucera Nov 29, 2021
1d98719
literal dependency evaluation
slavek-kucera Nov 30, 2021
97bf2f9
include processing stack in diagnostics from literals
slavek-kucera Nov 30, 2021
6379ade
reladdr literal reference should trigger halfword alignment
slavek-kucera Nov 30, 2021
67b280d
...
slavek-kucera Dec 1, 2021
47d80e6
...
slavek-kucera Dec 1, 2021
7e0a364
do not create the private section until needed
slavek-kucera Dec 1, 2021
dc8206c
tests
slavek-kucera Dec 1, 2021
2689e2d
fix cache issue related to reladdr transformation
slavek-kucera Dec 2, 2021
6aa3379
fix data definition extension parsing
slavek-kucera Dec 2, 2021
0d609b6
fix handling of private sections
slavek-kucera Dec 2, 2021
29329ad
fix attribute lookahead on expressions
slavek-kucera Dec 3, 2021
1ec8e76
review suggestions
slavek-kucera Dec 3, 2021
8de34c0
split ordinary_assembly_dependency_solver
slavek-kucera Dec 3, 2021
3cfa9e1
add test for bad literal attributes
slavek-kucera Dec 3, 2021
edcbaef
...
slavek-kucera Dec 3, 2021
1c17faa
run DC-like check when generating literal pool
slavek-kucera Dec 6, 2021
14846db
handle zero-length literals better
slavek-kucera Dec 6, 2021
dfea704
reladdr transform mask for mnemonics
slavek-kucera Dec 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion language_server/test/telemetry_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ TEST(telemetry, telemetry_broker)

//"textDocument/hover",R"#({"textDocument":{"uri":"file:///c%3A/test/stability.hlasm"},"position":{"line":0,"character":7}})#"_json),

std::thread lsp_thread([&broker, &lsp_server]() {
std::thread lsp_thread([&lsp_server]() {
lsp_server.message_received(
R"({"jsonrpc":"2.0","id":48,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///test_file"},"position":{"line":0,"character":2} }})"_json);
});
Expand Down
2 changes: 2 additions & 0 deletions parser_library/src/context/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ target_sources(parser_library PRIVATE
instruction.cpp
instruction.h
instruction_type.h
literal_pool.cpp
literal_pool.h
macro.cpp
macro.h
macro_param_data.cpp
Expand Down
4 changes: 3 additions & 1 deletion parser_library/src/context/hlasm_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ hlasm_context::hlasm_context(std::string file_name, asm_option asm_options, std:
add_global_system_vars();
}

hlasm_context::~hlasm_context() = default;

void hlasm_context::set_source_position(position pos) { source_stack_.back().current_instruction.pos = pos; }

void hlasm_context::set_source_indices(size_t begin_index, size_t end_index, size_t end_line)
Expand Down Expand Up @@ -647,7 +649,7 @@ C_t hlasm_context::get_type_attr(var_sym_ptr var_symbol, const std::vector<size_
if (value.empty())
return "O";

expressions::ca_symbol_attribute::try_extract_leading_symbol(value);
value = expressions::ca_symbol_attribute::try_extract_leading_symbol(value);

auto res = expressions::ca_constant::try_self_defining_term(value);
if (res)
Expand Down
3 changes: 2 additions & 1 deletion parser_library/src/context/hlasm_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include "ordinary_assembly/ordinary_assembly_context.h"
#include "processing_context.h"


namespace hlasm_plugin::parser_library::context {

// class helping to perform semantic analysis of hlasm source code
Expand Down Expand Up @@ -83,6 +82,7 @@ class hlasm_context
// last AINSERT virtual file id
size_t m_ainsert_id = 0;
bool m_end_reached = false;

void add_system_vars_to_scope();
void add_global_system_vars();

Expand All @@ -92,6 +92,7 @@ class hlasm_context
hlasm_context(std::string file_name = "",
asm_option asm_opts = {},
std::shared_ptr<id_storage> init_ids = std::make_shared<id_storage>());
~hlasm_context();

// gets name of file where is open-code located
const std::string& opencode_file_name() const;
Expand Down
2 changes: 1 addition & 1 deletion parser_library/src/context/id_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ class id_storage
const std::string* AGO;
const std::string* ACTR;
const std::string* AREAD;
const std::string* END;
const std::string* ALIAS;
const std::string* END;
well_known_strings(std::unordered_set<std::string>& ptr);

} const well_known;
Expand Down
197 changes: 197 additions & 0 deletions parser_library/src/context/literal_pool.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/*
* Copyright (c) 2021 Broadcom.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Broadcom, Inc. - initial API and implementation
*/

#include "literal_pool.h"

#include <algorithm>
#include <functional>

#include "context/ordinary_assembly/ordinary_assembly_context.h"
#include "context/ordinary_assembly/postponed_statement.h"
#include "diagnosable_ctx.h"
#include "ebcdic_encoding.h"
#include "hlasm_context.h"
#include "processing/statement.h"
#include "semantics/operand_impls.h"

namespace hlasm_plugin::parser_library::context {

id_index literal_pool::add_literal(const std::string& literal_text,
const std::shared_ptr<const expressions::data_definition>& dd,
range r,
size_t unique_id,
std::optional<address> loctr,
bool align_on_halfword)
{
unique_id = dd->references_loctr ? unique_id : 0;
if (auto lit = get_literal(m_current_literal_pool_generation, dd, unique_id))
return lit;

auto [it, inserted] = m_literals.try_emplace(
literal_id { m_current_literal_pool_generation, unique_id, dd }, literal_text, std::move(r), std::move(loctr));
// even if we end up inserting a duplicate
// we need to try to insert const expressions::data_definition->iterator relation
// because a single literal may be referenced by independent data_definitions
m_literals_genmap.try_emplace(literal_id { m_current_literal_pool_generation, unique_id, dd }, it);
// but we should not try to put logical duplicates on the pending queue
if (inserted)
{
m_pending_literals.emplace_back(it);
it->second.stack = hlasm_ctx.processing_stack();
}
it->second.align_on_halfword |= align_on_halfword;

return &it->second.text;
}

id_index literal_pool::get_literal(
size_t generation, const std::shared_ptr<const expressions::data_definition>& dd, size_t unique_id) const
{
unique_id = dd->references_loctr ? unique_id : 0;
auto it = m_literals_genmap.find(literal_id { generation, unique_id, dd });
if (it == m_literals_genmap.end())
return nullptr;
return &it->second->second.text;
}


class literal_pool::literal_postponed_statement : public context::postponed_statement,
public processing::resolved_statement
{
const literal_pool::literal_details* details;
semantics::operands_si op;
processing::op_code op_code;

static const semantics::remarks_si empty_remarks;
static const semantics::label_si empty_label;
static const semantics::instruction_si empty_instr;
static const processing::processing_format dc_format;

public:
literal_postponed_statement(const std::shared_ptr<const expressions::data_definition>& dd,
const literal_pool::literal_details& details,
id_storage& ids)
: details(&details)
, op(details.r, {})
, op_code(ids.add("DC"), instruction_type::ASM)
{
op.value.push_back(std::make_unique<semantics::data_def_operand>(dd, details.r));
}
const processing_stack_t& location_stack() const override { return details->stack; }
const processing::resolved_statement* resolved_stmt() const override { return this; }
const processing::op_code& opcode_ref() const override { return op_code; }
processing::processing_format format_ref() const override { return dc_format; }
const semantics::operands_si& operands_ref() const override { return op; }
const semantics::remarks_si& remarks_ref() const override { return empty_remarks; }
const range& stmt_range_ref() const override { return details->r; }
const semantics::label_si& label_ref() const override { return empty_label; }
const semantics::instruction_si& instruction_ref() const override { return empty_instr; }
std::pair<const diagnostic_op*, const diagnostic_op*> diagnostics() const override { return {}; };
};
const semantics::remarks_si literal_pool::literal_postponed_statement::empty_remarks({}, {});
const semantics::label_si literal_pool::literal_postponed_statement::empty_label(range {});
const semantics::instruction_si literal_pool::literal_postponed_statement::empty_instr(range {});
const processing::processing_format literal_pool::literal_postponed_statement::dc_format(
processing::processing_kind::ORDINARY, processing::processing_form::ASM, processing::operand_occurence::PRESENT);

void literal_pool::generate_pool(dependency_solver& solver, const diagnosable_ctx& diags)
{
ordinary_assembly_context& ord_ctx = hlasm_ctx.ord_ctx;

if (m_pending_literals.empty())
return;

for (auto& [it, size, alignment] : m_pending_literals)
{
const auto& lit = it->first.lit;
if (!lit->access_data_def_type()) // unknown type
continue;

size = (semantics::data_def_operand::get_operand_value(*lit, solver).get_length() + 7) / 8;
if (size == 0)
continue;

auto top_alignment = size | 16; // 16B length alignment is the top
alignment = (~top_alignment & top_alignment - 1) + 1;
}

std::stable_sort(m_pending_literals.begin(), m_pending_literals.end(), [](const auto& l, const auto& r) {
return l.alignment > r.alignment;
});

constexpr auto sectalign = doubleword;
ord_ctx.align(sectalign);

for (const auto& [it, size, alignment] : m_pending_literals)
{
const auto& lit_key = it->first;
const auto& lit = lit_key.lit;
const auto& lit_val = it->second;

if (!lit->access_data_def_type()) // unknown type
continue;

// TODO: warn on align > sectalign

bool cycle_ok = ord_ctx.create_symbol(&lit_val.text,
ord_ctx.align(lit_val.align_on_halfword ? halfword : no_align),
symbol_attributes(symbol_origin::DAT,
ebcdic_encoding::a2e[(unsigned char)lit->get_type_attribute()],
lit->get_length_attribute(solver)),
{});

if (size == 0)
{
diags.add_diagnostic(diagnostic_op::error_D031(it->second.r));
continue;
}

ord_ctx.reserve_storage_area(size, no_align);

if (!cycle_ok)
diags.add_diagnostic(diagnostic_op::error_E033(it->second.r));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am reasonably sure that this should never really happen, but not 100%.

else if (lit->get_dependencies(solver).contains_dependencies())
{
auto adder = ord_ctx.symbol_dependencies.add_dependencies(
std::make_unique<literal_postponed_statement>(lit, lit_val, hlasm_ctx.ids()),
{ lit_val.loctr, lit_key.generation, lit_key.unique_id });
adder.add_dependency();
adder.finish();
}
else
{
auto ddt = lit->access_data_def_type();
if (!ddt) // unknown type
continue;

auto ddo = semantics::data_def_operand::get_operand_value(*lit, solver);
ddt->check_DC(ddo, diagnostic_collector(&diags, lit_val.stack));
}
}

m_pending_literals.clear();
++m_current_literal_pool_generation;
}

bool literal_pool::literal_id::is_similar(const literal_id& ld) const noexcept
{
return generation == ld.generation && unique_id == ld.unique_id && utils::is_similar(lit, ld.lit);
}

size_t literal_pool::literal_definition_hasher::operator()(const literal_id& ld) const noexcept
{
return ld.lit->hash() ^ ld.generation ^ ld.unique_id;
}

} // namespace hlasm_plugin::parser_library::context
123 changes: 123 additions & 0 deletions parser_library/src/context/literal_pool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright (c) 2021 Broadcom.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Broadcom, Inc. - initial API and implementation
*/

#ifndef HLASMPLUGIN_PARSERLIBRARY_LITERAL_POOL_H
#define HLASMPLUGIN_PARSERLIBRARY_LITERAL_POOL_H

#include <unordered_map>
#include <unordered_set>

#include "expressions/data_definition.h"
#include "id_storage.h"
#include "location.h"
#include "processing_context.h"
#include "utils/similar.h"

namespace hlasm_plugin::parser_library::context {
class hlasm_context;

class literal_pool
{
struct literal_id
{
size_t generation;
size_t unique_id;
std::shared_ptr<const expressions::data_definition> lit;

bool is_similar(const literal_id&) const noexcept;
};
struct literal_details
{
std::string text;
range r;
std::optional<address> loctr;
processing_stack_t stack;
bool align_on_halfword = false;

literal_details(std::string text, range r, std::optional<address> loctr)
: text(std::move(text))
, r(r)
, loctr(std::move(loctr))
{}

literal_details(std::string text, range r, std::optional<address> loctr, processing_stack_t stack)
: text(std::move(text))
, r(r)
, loctr(std::move(loctr))
, stack(std::move(stack))
{}
};
class literal_postponed_statement;
struct literal_definition_hasher
{
size_t operator()(const literal_id&) const noexcept;
};
size_t m_current_literal_pool_generation = 0;

struct literal_id_helper
{
size_t operator()(const literal_id& p) const noexcept
{
return std::hash<size_t>()(p.generation) ^ std::hash<size_t>()(p.unique_id)
^ std::hash<const expressions::data_definition*>()(p.lit.get());
}
bool operator()(const literal_id& l, const literal_id& r) const noexcept
{
return l.lit == r.lit && l.generation == r.generation && l.unique_id == r.unique_id;
}
};

std::unordered_map<literal_id, literal_details, literal_definition_hasher, decltype(utils::is_similar)> m_literals;
std::unordered_map<literal_id, decltype(m_literals)::const_iterator, literal_id_helper, literal_id_helper>
m_literals_genmap;

struct pending_literal
{
decltype(m_literals)::const_iterator literal;
size_t size = 0;
size_t alignment = 0;

explicit pending_literal(decltype(m_literals)::const_iterator l) noexcept
: literal(l)
{}
};

std::vector<pending_literal> m_pending_literals;

hlasm_context& hlasm_ctx;

public:
explicit literal_pool(hlasm_context& hlasm_ctx)
: hlasm_ctx(hlasm_ctx)
{}

id_index add_literal(const std::string& literal_text,
const std::shared_ptr<const expressions::data_definition>& dd,
range r,
size_t unique_id,
std::optional<address> loctr,
bool align_on_halfword);
id_index get_literal(
size_t generation, const std::shared_ptr<const expressions::data_definition>& dd, size_t unique_id) const;

void generate_pool(dependency_solver& solver, const diagnosable_ctx& diags);
size_t current_generation() const { return m_current_literal_pool_generation; }

// testing
size_t get_pending_count() const { return m_pending_literals.size(); }
};

} // namespace hlasm_plugin::parser_library::context

#endif
Loading