Skip to content

Commit

Permalink
Function pointer conversion
Browse files Browse the repository at this point in the history
Add function / pointer conversion llvm operators. Accept these operators
as top-level nodes in the various transformation passes, and handle them in
instruction conversion.

There are presently no "users" of these operators or anything that puts them
into the graph -- so this is preparatory for making function and pointer
distinction in a later commit.
  • Loading branch information
caleridas committed Jan 4, 2025
1 parent a145d70 commit 8117aaa
Show file tree
Hide file tree
Showing 7 changed files with 302 additions and 1 deletion.
2 changes: 2 additions & 0 deletions jlm/llvm/Makefile.sub
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ libllvm_SOURCES = \
jlm/llvm/ir/operators/alloca.cpp \
jlm/llvm/ir/operators/call.cpp \
jlm/llvm/ir/operators/delta.cpp \
jlm/llvm/ir/operators/FunctionPointer.cpp \
jlm/llvm/ir/operators/GetElementPtr.cpp \
jlm/llvm/ir/operators/lambda.cpp \
jlm/llvm/ir/operators/Load.cpp \
Expand Down Expand Up @@ -123,6 +124,7 @@ libllvm_HEADERS = \
jlm/llvm/ir/operators/Load.hpp \
jlm/llvm/ir/operators/MemCpy.hpp \
jlm/llvm/ir/operators/MemoryStateOperations.hpp \
jlm/llvm/ir/operators/FunctionPointer.hpp \
jlm/llvm/ir/operators/GetElementPtr.hpp \
jlm/llvm/ir/operators/delta.hpp \
jlm/llvm/ir/operators/Store.hpp \
Expand Down
25 changes: 24 additions & 1 deletion jlm/llvm/backend/jlm2llvm/instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <jlm/llvm/ir/cfg-node.hpp>
#include <jlm/llvm/ir/ipgraph-module.hpp>
#include <jlm/llvm/ir/operators.hpp>
#include <jlm/llvm/ir/operators/FunctionPointer.hpp>
#include <jlm/llvm/ir/operators/MemoryStateOperations.hpp>

#include <jlm/llvm/backend/jlm2llvm/context.hpp>
Expand Down Expand Up @@ -1001,6 +1002,26 @@ convert(
return nullptr;
}

static ::llvm::Value *
convert(
const PointerToFunctionOperation &,
const std::vector<const variable *> & operands,
::llvm::IRBuilder<> &,
context & ctx)
{
return ctx.value(operands[0]);
}

static ::llvm::Value *
convert(
const FunctionToPointerOperation &,
const std::vector<const variable *> & operands,
::llvm::IRBuilder<> &,
context & ctx)
{
return ctx.value(operands[0]);
}

template<class OP>
static ::llvm::Value *
convert(
Expand Down Expand Up @@ -1094,7 +1115,9 @@ convert_operation(
{ typeid(CallEntryMemoryStateMergeOperation),
convert<CallEntryMemoryStateMergeOperation> },
{ typeid(CallExitMemoryStateSplitOperation),
convert<CallExitMemoryStateSplitOperation> } });
convert<CallExitMemoryStateSplitOperation> },
{ typeid(PointerToFunctionOperation), convert<PointerToFunctionOperation> },
{ typeid(FunctionToPointerOperation), convert<FunctionToPointerOperation> } });
/* FIXME: AddrSpaceCast instruction is not supported */

JLM_ASSERT(map.find(std::type_index(typeid(op))) != map.end());
Expand Down
158 changes: 158 additions & 0 deletions jlm/llvm/ir/operators/FunctionPointer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* Copyright 2024 Helge Bahmann <[email protected]>
* See COPYING for terms of redistribution.
*/

#include <jlm/llvm/ir/operators/FunctionPointer.hpp>
#include <jlm/rvsdg/simple-node.hpp>

namespace jlm::llvm
{

FunctionToPointerOperation::~FunctionToPointerOperation() noexcept
{}

FunctionToPointerOperation::FunctionToPointerOperation(std::shared_ptr<const llvm::FunctionType> fn)
: unary_op(fn, llvm::PointerType::Create()),
FunctionType_(std::move(fn))
{}

bool
FunctionToPointerOperation::operator==(const Operation & other) const noexcept
{
if (auto o = dynamic_cast<const FunctionToPointerOperation *>(&other))
{
return *FunctionType() == *o->FunctionType();
}
else
{
return false;
}
}

[[nodiscard]] std::string
FunctionToPointerOperation::debug_string() const
{
return "FunPtr(" + FunctionType()->debug_string() + ")";
}

[[nodiscard]] std::unique_ptr<rvsdg::Operation>
FunctionToPointerOperation::copy() const
{
return Create(FunctionType());
}

rvsdg::unop_reduction_path_t
FunctionToPointerOperation::can_reduce_operand(const jlm::rvsdg::output * arg) const noexcept
{
if (auto node = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*arg))
{
if (auto op = dynamic_cast<const PointerToFunctionOperation *>(&node->GetOperation()))
{
if (*op->FunctionType() == *FunctionType())
{
return rvsdg::unop_reduction_inverse;
}
}
}
return rvsdg::unop_reduction_none;
}

jlm::rvsdg::output *
FunctionToPointerOperation::reduce_operand(
rvsdg::unop_reduction_path_t path,
jlm::rvsdg::output * arg) const
{
if (auto node = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*arg))
{
if (auto op = dynamic_cast<const PointerToFunctionOperation *>(&node->GetOperation()))
{
if (*op->FunctionType() == *FunctionType())
{
return node->input(0)->origin();
}
}
}
return arg;
}

std::unique_ptr<FunctionToPointerOperation>
FunctionToPointerOperation::Create(std::shared_ptr<const llvm::FunctionType> fn)
{
return std::make_unique<FunctionToPointerOperation>(std::move(fn));
}

PointerToFunctionOperation::~PointerToFunctionOperation() noexcept
{}

PointerToFunctionOperation::PointerToFunctionOperation(std::shared_ptr<const llvm::FunctionType> fn)
: unary_op(llvm::PointerType::Create(), fn),
FunctionType_(std::move(fn))
{}

bool
PointerToFunctionOperation::operator==(const Operation & other) const noexcept
{
if (auto o = dynamic_cast<const PointerToFunctionOperation *>(&other))
{
return *FunctionType() == *o->FunctionType();
}
else
{
return false;
}
}

[[nodiscard]] std::string
PointerToFunctionOperation::debug_string() const
{
return "PtrFun(" + FunctionType()->debug_string() + ")";
}

[[nodiscard]] std::unique_ptr<rvsdg::Operation>
PointerToFunctionOperation::copy() const
{
return Create(FunctionType());
}

rvsdg::unop_reduction_path_t
PointerToFunctionOperation::can_reduce_operand(const jlm::rvsdg::output * arg) const noexcept
{
if (auto node = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*arg))
{
if (auto op = dynamic_cast<const FunctionToPointerOperation *>(&node->GetOperation()))
{
if (*op->FunctionType() == *FunctionType())
{
return rvsdg::unop_reduction_inverse;
}
}
}
return rvsdg::unop_reduction_none;
}

jlm::rvsdg::output *
PointerToFunctionOperation::reduce_operand(
rvsdg::unop_reduction_path_t path,
jlm::rvsdg::output * arg) const
{
if (auto node = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*arg))
{
if (auto op = dynamic_cast<const FunctionToPointerOperation *>(&node->GetOperation()))
{
if (*op->FunctionType() == *FunctionType())
{
return node->input(0)->origin();
}
}
}
return arg;
}

std::unique_ptr<PointerToFunctionOperation>
PointerToFunctionOperation::Create(std::shared_ptr<const llvm::FunctionType> fn)
{
return std::make_unique<PointerToFunctionOperation>(std::move(fn));
}

}
95 changes: 95 additions & 0 deletions jlm/llvm/ir/operators/FunctionPointer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright 2024 Helge Bahmann <[email protected]>
* See COPYING for terms of redistribution.
*/

#ifndef JLM_LLVM_IR_OPERATORS_FUNCTIONPOINTER_HPP
#define JLM_LLVM_IR_OPERATORS_FUNCTIONPOINTER_HPP

#include <jlm/llvm/ir/tac.hpp>
#include <jlm/llvm/ir/types.hpp>
#include <jlm/rvsdg/bitstring/type.hpp>
#include <jlm/rvsdg/unary.hpp>

namespace jlm::llvm
{

/**
\brief Get address of compiled function object.
*/
class FunctionToPointerOperation final : public rvsdg::unary_op
{
public:
~FunctionToPointerOperation() noexcept override;

FunctionToPointerOperation(std::shared_ptr<const llvm::FunctionType> fn);

bool
operator==(const Operation & other) const noexcept override;

[[nodiscard]] std::string
debug_string() const override;

[[nodiscard]] std::unique_ptr<Operation>
copy() const override;

rvsdg::unop_reduction_path_t
can_reduce_operand(const jlm::rvsdg::output * arg) const noexcept override;

jlm::rvsdg::output *
reduce_operand(rvsdg::unop_reduction_path_t path, jlm::rvsdg::output * arg) const override;

static std::unique_ptr<FunctionToPointerOperation>
Create(std::shared_ptr<const llvm::FunctionType> fn);

inline const std::shared_ptr<const jlm::llvm::FunctionType> &
FunctionType() const noexcept
{
return FunctionType_;
}

private:
std::shared_ptr<const llvm::FunctionType> FunctionType_;
};

/**
\brief Interpret pointer as callable function.
*/
class PointerToFunctionOperation final : public rvsdg::unary_op
{
public:
~PointerToFunctionOperation() noexcept override;

PointerToFunctionOperation(std::shared_ptr<const llvm::FunctionType> fn);

bool
operator==(const Operation & other) const noexcept override;

[[nodiscard]] std::string
debug_string() const override;

[[nodiscard]] std::unique_ptr<rvsdg::Operation>
copy() const override;

rvsdg::unop_reduction_path_t
can_reduce_operand(const jlm::rvsdg::output * arg) const noexcept override;

jlm::rvsdg::output *
reduce_operand(rvsdg::unop_reduction_path_t path, jlm::rvsdg::output * arg) const override;

static std::unique_ptr<PointerToFunctionOperation>
Create(std::shared_ptr<const llvm::FunctionType> fn);

inline const std::shared_ptr<const llvm::FunctionType> &
FunctionType() const noexcept
{
return FunctionType_;
}

private:
std::shared_ptr<const llvm::FunctionType> FunctionType_;
};

}

#endif // JLM_LLVM_IR_OPERATORS_FUNCTIONPOINTER_HPP
7 changes: 7 additions & 0 deletions jlm/llvm/opt/InvariantValueRedirection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <jlm/llvm/ir/operators/call.hpp>
#include <jlm/llvm/ir/operators/delta.hpp>
#include <jlm/llvm/ir/operators/FunctionPointer.hpp>
#include <jlm/llvm/ir/RvsdgModule.hpp>
#include <jlm/llvm/opt/InvariantValueRedirection.hpp>
#include <jlm/rvsdg/gamma.hpp>
Expand Down Expand Up @@ -84,6 +85,12 @@ InvariantValueRedirection::RedirectInRootRegion(rvsdg::Graph & rvsdg)
// Nothing needs to be done.
// Delta nodes are irrelevant for invariant value redirection.
}
else if (
is<FunctionToPointerOperation>(node->GetOperation())
|| is<PointerToFunctionOperation>(node->GetOperation()))
{
// Nothing needs to be done.
}
else
{
JLM_UNREACHABLE("Unhandled node type.");
Expand Down
9 changes: 9 additions & 0 deletions jlm/llvm/opt/alias-analyses/RegionAwareMemoryNodeProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

#include <jlm/llvm/ir/operators/alloca.hpp>
#include <jlm/llvm/ir/operators/FunctionPointer.hpp>
#include <jlm/llvm/ir/operators/lambda.hpp>
#include <jlm/llvm/ir/operators/Store.hpp>
#include <jlm/llvm/ir/RvsdgModule.hpp>
Expand Down Expand Up @@ -874,6 +875,14 @@ RegionAwareMemoryNodeProvider::Propagate(const RvsdgModule & rvsdgModule)
// Nothing needs to be done for delta nodes.
continue;
}
else if (
is<FunctionToPointerOperation>(node->GetOperation())
|| is<PointerToFunctionOperation>(node->GetOperation()))
{
// Few operators may appear as top-level constructs and simply must
// be ignored.
continue;
}
else
{
JLM_UNREACHABLE("Unhandled node type!");
Expand Down
7 changes: 7 additions & 0 deletions jlm/llvm/opt/alias-analyses/TopDownMemoryNodeEliminator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* See COPYING for terms of redistribution.
*/

#include <jlm/llvm/ir/operators/FunctionPointer.hpp>
#include <jlm/llvm/opt/alias-analyses/MemoryNodeProvider.hpp>
#include <jlm/llvm/opt/alias-analyses/TopDownMemoryNodeEliminator.hpp>
#include <jlm/rvsdg/traverser.hpp>
Expand Down Expand Up @@ -492,6 +493,12 @@ TopDownMemoryNodeEliminator::EliminateTopDownRootRegion(rvsdg::Region & region)
{
// Nothing needs to be done.
}
else if (
is<FunctionToPointerOperation>(node->GetOperation())
|| is<PointerToFunctionOperation>(node->GetOperation()))
{
// Nothing needs to be done.
}
else
{
JLM_UNREACHABLE("Unhandled node type!");
Expand Down

0 comments on commit 8117aaa

Please sign in to comment.