#custom ir

71 messages · Page 1 of 1 (latest)

weary mesaBOT
#

When your question is answered use !solved or the button below to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

fluid raft
#

whats an ir?

vital flame
#

i guess ill look at this

#

please use structs and free functions

#

it’d be like, idk, 30 mins max to rewrite this module

#

your current one is over engineered garbage

what you have and need to improve

  • OOP abuse
  • Variant_wrapper(?)
  • what is s_index global for? i don’t think you need globals
#

and why the hell does this resemble AST when it’s supposed to be an IR

violet ridge
#

it becomes messy either way

vital flame
#

how?🤔

violet ridge
#

like I want this exact functionality but preferably more clean

vital flame
#

is it because of triton?

#

i dunno about it but this isn’t how IRs are supposed to be

violet ridge
#

not because of triton

vital flame
#

mkay

#

ill go to sleep now

#

do ping me later if you still can’t solve it

violet ridge
#

kk sure

vital flame
#

i see some solutions but it’s almost 6 in the morning

#

cya

violet ridge
#

I still believe variants is the way to go but not sure

violet ridge
#

bump

vital flame
#

bump

violet ridge
#

ok I realized the std::optional in the visitor struct makes 0 sense

vital flame
#

since you can't figure it out

#
export module ir;

import std;
import <triton/context.hpp>;

namespace ir {

static unsigned s_index{};

struct Variable { 
    std::string name; 
    std::size_t size; 
    Variable(std::size_t sz) : name{std::format("t{}", ++s_index)}, size{sz} {}
    Variable(std::string_view n, std::size_t sz) : name{n}, size{sz} {}
};
struct Register { 
    triton::arch::Register reg; 
    Register(const triton::arch::Register& r) : reg{r} {}
};
struct Immediate { 
    std::uintptr_t value; 
    std::size_t size; 
    Immediate(std::uintptr_t v, std::size_t sz = 8) : value{v}, size{sz} {}
    Immediate(const triton::arch::Immediate& imm) : value{imm.getValue()}, size{imm.getSize()} {}
};

using Leaf = std::variant<Variable, Register, Immediate>;

struct Memory { Leaf expr; triton::arch::Register seg; std::size_t size; };
struct Extract { Leaf expr; std::size_t hi, lo; };
struct Extend { Leaf expr; std::size_t size; };
struct Sign_extend { Leaf expr; std::size_t size; };
struct Zero_extend { Leaf expr; std::size_t size; };
struct Inc { Leaf expr; std::size_t size; };
struct Dec { Leaf expr; std::size_t size; };
struct Neg { Leaf expr; std::size_t size; };
struct Not { Leaf expr; std::size_t size; };

using Expr = std::variant<
    Variable, Register, Immediate,
    Memory, Extract, Extend, Sign_extend, Zero_extend,
    Inc, Dec, Neg, Not
>;

struct Push { Expr expr; };
struct Assign { Expr lhs, rhs; };
using Instr = std::variant<Push, Assign>;

inline std::string to_string(const Variable& v) { return v.name; }
inline std::string to_string(const Register& r) { return r.reg.getName(); }
inline std::string to_string(const Immediate& i) { return std::format("{:#x}", i.value); }
inline std::string to_string(const Leaf& l) { return std::visit([](auto&& v){ return to_string(v); }, l); }

inline std::size_t get_size(const Variable& v) { return v.size; }
inline std::size_t get_size(const Register& r) { return r.reg.getSize(); }
inline std::size_t get_size(const Immediate& i) { return i.size; }
inline std::size_t get_size(const Leaf& l) { return std::visit([](auto&& v){ return get_size(v); }, l); }
} // namespace ir
violet ridge
#

@vital flame this doesn't preserve the original functionality though

#

I want to be able to do something like this

weary mesaBOT
#

@violet ridge Has your question been resolved? If so, type !solved :)

vital flame
#
inline std::string to_string(const Expr& e) {
    return std::visit([](auto&& v) -> std::string {
        using T = std::decay_t<decltype(v)>;
        if constexpr (std::same_as<T, Variable> || std::same_as<T, Register> || std::same_as<T, Immediate>) {
            return to_string(v);
        } else if constexpr (std::same_as<T, Memory>) {
            return std::format("mem[{}]", to_string(v.expr));
        } else if constexpr (std::same_as<T, Inc>) {
            return std::format("inc({})", to_string(v.expr));
        } else {
            return "unknown";
        }
    }, e);
}

this should already solve your problem

#

you have 3 different ways to write your dispatch or whatever that is

violet ridge
# vital flame you have 3 different ways to write your dispatch or whatever that is

this is great but how can I do something like: ```cpp
std::vector<Instr> instructions;
instructions.emplace_back(Push{Register{10}});
instructions.emplace_back(Push{Immediate{20}});
instructions.emplace_back(Assign{Register{30}, Immediate{40}});

for (const auto& instruction : instructions) {
    if (auto* push = get_if<ir::Push>(instruction)) {
        std::println("push {}", to_string(push));
    }
}
std::println();```
vital flame
violet ridge
#

oh

vital flame
#

yeah, the visitor visits and dispatch

#

wow why delete

violet ridge
#

now I get it, yeah ur code is awesome

vital flame
#

you just gotta add more branches

#

this is ideally not the best design in my perspective but if it works for you then cool

violet ridge
#

uhh what is this for

#
template<typename... Fs>
struct overloaded : Fs... { using Fs::operator()...; };```
vital flame
#

see the first approach

#

it’s an overloading helper

violet ridge
#

ic

vital flame
#

for c++23 and beyond, idk if you can directly use multiple lambdas without the overload helper

#

i don’t really use variants

violet ridge
#

can we avoid something like this? cpp using T = std::decay_t<decltype(v)>; if constexpr (std::same_as<T, Variable> || std::same_as<T, Register> || std::same_as<T, Immediate>) {

#

like having to explicitly type each one

#

and just use using Leaf = std::variant<Variable, Register, Immediate>; somehow

vital flame
#

not that i know of unfortunately

#

aside from overload helper

#

see approach (2)

violet ridge
#

oh nice u can just do

#
if constexpr (std::constructible_from<Leaf, T>) {
            return to_string(v);
        }```
#

alright will try to add this to the project and if there are no probs will mark this as solved

#

thanks for the help

weary mesaBOT
#

@violet ridge Has your question been resolved? If so, type !solved :)

violet ridge
#

ok so my understanding is basically, you changed expr, leaf and inst from being classes to just a std::variant, and instead wrote free functions with ADL

vital flame
#

uh huh

#

yeah

#

i just have no idea why the original code snippet has so much bookkeeping

weary mesaBOT
#

This question is being automatically marked as stale.
If your question has been answered, type !solved.
If your question is not answered feel free to bump the post or re-ask.
Take a look at !howto ask for tips on improving your question.

violet ridge
#

ok ty for the help, this is the final design I came up with

weary mesaBOT
#

@violet ridge Has your question been resolved? If so, type !solved :)

violet ridge
#

!solved

weary mesaBOT
#

Thank you and let us know if you have any more questions!

This thread is now set to auto-hide after an hour of inactivity