Skip to content

Commit

Permalink
Merge pull request #136 from zyantific/label-lookup
Browse files Browse the repository at this point in the history
Some improvements
  • Loading branch information
ZehMatt committed Jul 2, 2024
2 parents a6c3a87 + 01b57ff commit a18fa34
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 4 deletions.
31 changes: 31 additions & 0 deletions tests/src/tests/tests.program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,4 +316,35 @@ namespace zasm::tests
}
}

TEST(ProgramTests, TestLabelNodeLookup)
{
Program program(MachineMode::AMD64);

x86::Assembler assembler(program);

auto label = assembler.createLabel();
ASSERT_EQ(assembler.mov(x86::eax, Imm(0)), ErrorCode::None);
ASSERT_EQ(assembler.mov(x86::eax, Imm(1)), ErrorCode::None);
ASSERT_EQ(assembler.mov(x86::eax, Imm(2)), ErrorCode::None);
ASSERT_EQ(assembler.bind(label), ErrorCode::None);
ASSERT_EQ(assembler.mov(x86::eax, Imm(3)), ErrorCode::None);

auto* labelNode = program.getNodeForLabel(label);
ASSERT_NE(labelNode, nullptr);

ASSERT_EQ(labelNode->holds<Label>(), true);
ASSERT_EQ(labelNode->get<Label>().getId(), label.getId());

auto* nextNode = labelNode->getNext();
ASSERT_NE(nextNode, nullptr);

ASSERT_EQ(nextNode->holds<Instruction>(), true);
const auto& instr = nextNode->get<Instruction>();

ASSERT_EQ(instr.isOperandType<Imm>(1), true);

const auto& imm = instr.getOperand<1, Imm>();
ASSERT_EQ(imm.value<int>(), 3);
}

} // namespace zasm::tests
81 changes: 79 additions & 2 deletions zasm/include/zasm/base/instruction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ namespace zasm
/// ex.: x86::Attribs::Lock
/// </summary>
/// <param name="attrib">Attributes to add</param>
/// <returns>Instruction&</returns>
/// <returns>*this</returns>
constexpr TBase& addAttribs(Attribs attrib)
{
_attribs = _attribs | attrib;
Expand All @@ -109,13 +109,18 @@ namespace zasm
/// ex.: x86::Attribs::Lock
/// </summary>
/// <param name="attrib">Attributes to remove</param>
/// <returns>Instruction&</returns>
/// <returns>*this</returns>
constexpr TBase& removeAttribs(Attribs attrib)
{
_attribs = _attribs & ~attrib;
return static_cast<TBase&>(*this);
}

/// <summary>
/// Adds a new operand to the instruction increasing the operand count by one.
/// </summary>
/// <param name="val">New operand</param>
/// <returns>*this</returns>
constexpr TBase& addOperand(const Operand& val) noexcept
{
assert(_opCount < _operands.size());
Expand All @@ -127,6 +132,12 @@ namespace zasm
return static_cast<TBase&>(*this);
}

/// <summary>
/// Sets the operand at the specified index, an already existing operand must exist at the index otherwise its a no-op.
/// </summary>
/// <param name="index"></param>
/// <param name="val"></param>
/// <returns>*this</returns>
constexpr TBase& setOperand(std::size_t index, const Operand& val) noexcept
{
assert(index < _opCount);
Expand All @@ -138,21 +149,39 @@ namespace zasm
return static_cast<TBase&>(*this);
}

/// <summary>
/// Returns the array to the operands storage, use getOperandCount to get the amount of used operands.
/// </summary>
/// <returns>Reference to operands</returns>
constexpr const Operands& getOperands() const noexcept
{
return _operands;
}

/// <summary>
/// Returns the array to the operands storage, use getOperandCount to get the amount of used operands.
/// </summary>
/// <returns>Reference to operands</returns>
constexpr Operands& getOperands() noexcept
{
return _operands;
}

/// <summary>
/// Returns the amount of used operands.
/// </summary>
/// <returns>Operand count</returns>
constexpr std::size_t getOperandCount() const noexcept
{
return _opCount;
}

/// <summary>
/// Returns the a reference to the operand at the specified compile time index if it is of the specified type T,
/// </summary>
/// <typeparam name="T">Expected operand type</typeparam>
/// <typeparam name="TIndex">Operand index</typeparam>
/// <returns>Reference to operand as T</returns>
template<std::size_t TIndex, typename T = Operand> constexpr const T& getOperand() const
{
if constexpr (std::is_same_v<T, Operand>)
Expand All @@ -166,6 +195,12 @@ namespace zasm
}
}

/// <summary>
/// Returns the a reference to the operand at the specified compile time index if it is of the specified type T,
/// </summary>
/// <typeparam name="T">Expected operand type</typeparam>
/// <typeparam name="TIndex">Operand index</typeparam>
/// <returns>Reference to operand as T</returns>
template<std::size_t TIndex, typename T = Operand> constexpr T& getOperand()
{
if constexpr (std::is_same_v<T, Operand>)
Expand All @@ -179,6 +214,13 @@ namespace zasm
}
}

/// <summary>
/// Returns the a reference to the operand at the specified index if it is of the specified type T,
/// will throw if the type does not match.
/// </summary>
/// <typeparam name="T">Expected operand type</typeparam>
/// <param name="index">Operand index</param>
/// <returns>A reference to the operand as T</returns>
template<typename T = Operand> constexpr const T& getOperand(std::size_t index) const
{
if constexpr (std::is_same_v<T, Operand>)
Expand All @@ -192,6 +234,13 @@ namespace zasm
}
}

/// <summary>
/// Returns the a reference to the operand at the specified index if it is of the specified type T,
/// will throw if the type does not match.
/// </summary>
/// <typeparam name="T">Expected operand type</typeparam>
/// <param name="index">Operand index</param>
/// <returns>A reference to the operand as T</returns>
template<typename T = Operand> constexpr T& getOperand(std::size_t index)
{
if constexpr (std::is_same_v<T, Operand>)
Expand All @@ -205,6 +254,12 @@ namespace zasm
}
}

/// <summary>
/// Returns the operand at the specified index if it is of the specified type T, otherwise nullptr.
/// </summary>
/// <typeparam name="T">Expected operand type</typeparam>
/// <param name="index">Operand index</param>
/// <returns>The operand as T if the type matches, otherwise nullptr</returns>
template<typename T> constexpr const T* getOperandIf(std::size_t index) const noexcept
{
if (index >= _opCount || index >= _operands.size())
Expand All @@ -216,6 +271,12 @@ namespace zasm
return operand.template getIf<T>();
}

/// <summary>
/// Returns the operand at the specified index if it is of the specified type T, otherwise nullptr.
/// </summary>
/// <typeparam name="T">Expected operand type</typeparam>
/// <param name="index">Operand index</param>
/// <returns>The operand as T if the type matches, otherwise nullptr</returns>
template<typename T> constexpr T* getOperandIf(std::size_t index) noexcept
{
if (index >= _opCount || index >= _operands.size())
Expand All @@ -225,6 +286,22 @@ namespace zasm
auto& operand = _operands[index];
return operand.template getIf<T>();
}

/// <summary>
/// Checks if the operand at the specified index is of the specified type T.
/// </summary>
/// <typeparam name="T">The type to check</typeparam>
/// <param name="index">Operand index</param>
/// <returns>True if the operand is type T</returns>
template<typename T> constexpr bool isOperandType(std::size_t index) const noexcept
{
if (index >= _opCount || index >= _operands.size())
{
return false;
}
const auto& operand = _operands[index];
return operand.template holds<T>();
}
};

} // namespace zasm
14 changes: 14 additions & 0 deletions zasm/include/zasm/program/program.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,13 @@ namespace zasm
/// <returns>Returns LabelData on success, Error on failure.</returns>
Expected<LabelData, Error> getLabelData(const Label& label) const noexcept;

/// <summary>
/// Returns the node for which the label is bound to. The node holds the Label.
/// </summary>
/// <param name="label">Label</param>
/// <returns>Node for which the label is bound to or null if the label is invalid or not bound</returns>
Node* getNodeForLabel(const Label& label);

public:
/// <summary>
/// Creates a new section that can be used to segment code and data.
Expand Down Expand Up @@ -304,6 +311,13 @@ namespace zasm
/// <param name="align">The new alignment</param>
/// <returns>Error::None on success otherwise see Error</returns>
Error setSectionAlign(const Section& section, std::int32_t align) noexcept;

/// <summary>
/// Returns the node for which the section is bound to. The node holds the Section.
/// </summary>
/// <param name="section">Section</param>
/// <returns>Node for which the section is bound to or null if the section is invalid or not bound</returns>
Node* getNodeForSection(const Section& section);
};

} // namespace zasm
34 changes: 34 additions & 0 deletions zasm/src/zasm/src/program/program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,40 @@ namespace zasm
return nodeMap[nodeIdx];
}

Node* Program::getNodeForLabel(const Label& label)
{
if (!label.isValid())
{
return nullptr;
}

const auto entryIdx = static_cast<std::size_t>(label.getId());
if (entryIdx >= _state->labels.size())
{
return nullptr;
}

auto& entry = _state->labels[entryIdx];
return entry.node;
}

Node* Program::getNodeForSection(const Section& section)
{
if (!section.isValid())
{
return nullptr;
}

const auto entryIdx = static_cast<std::size_t>(section.getId());
if (entryIdx >= _state->sections.size())
{
return nullptr;
}

auto& entry = _state->sections[entryIdx];
return entry.node;
}

template<bool TNotify, typename F, typename... TArgs>
static void notifyObservers(const F&& func, const std::vector<Observer*>& observers, TArgs&&... args) noexcept
{
Expand Down
4 changes: 2 additions & 2 deletions zasm/src/zasm/src/program/program.state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ namespace zasm::detail
StringPool::Id moduleId{ StringPool::Id::Invalid };

// The node that holds/binds the label in the list.
const zasm::Node* node{};
zasm::Node* node{};
};

struct SectionData
Expand All @@ -43,7 +43,7 @@ namespace zasm::detail
std::int32_t align{};

// The node that holds/binds the label in the list.
const zasm::Node* node{};
zasm::Node* node{};
};

struct NodeStorage
Expand Down

0 comments on commit a18fa34

Please sign in to comment.