Newer
Older
minerva / Userland / Libraries / LibDisassembly / riscv64 / FD.h
@minerva minerva on 13 Jul 14 KB Initial commit
/*
 * Copyright (c) 2023, kleines Filmröllchen <filmroellchen@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <LibDisassembly/riscv64/Instruction.h>

// F and D extensions.
namespace Disassembly::RISCV64 {

// Table 11.3; IEEE 754 floating-point "format" or width field.
enum class FloatWidth : u8 {
    // binary32
    Single = 0,
    // binary64
    Double = 1,
    // binary16
    Half = 2,
    // binary128
    Quad = 3,
};

constexpr DataWidth float_width_to_data_width(FloatWidth width)
{
    switch (width) {
    case FloatWidth::Single:
        return DataWidth::Word;
    case FloatWidth::Double:
        return DataWidth::DoubleWord;
    case FloatWidth::Half:
        return DataWidth::Halfword;
    case FloatWidth::Quad:
        return DataWidth::QuadWord;
    }
    VERIFY_NOT_REACHED();
}

constexpr FloatWidth data_width_to_float_width(DataWidth width)
{
    switch (width) {
    case DataWidth::Word:
        return FloatWidth::Single;
    case DataWidth::DoubleWord:
        return FloatWidth::Double;
    case DataWidth::Halfword:
        return FloatWidth::Half;
    case DataWidth::QuadWord:
        return FloatWidth::Quad;
    case DataWidth::Byte:
        VERIFY_NOT_REACHED();
    }
    VERIFY_NOT_REACHED();
}

class FloatInstruction : public InstructionImpl {
public:
    virtual ~FloatInstruction() = default;
    bool operator==(FloatInstruction const&) const = default;

    // When used in loads and stores, we can coerce a float width to its equivalent memory access type.
    MemoryAccessMode memory_width() const
    {
        return { .width = float_width_to_data_width(m_width), .signedness = Signedness::Signed };
    }
    FloatWidth width() const { return m_width; }

    FloatInstruction(FloatWidth width)
        : m_width(width)
    {
    }

private:
    FloatWidth m_width;
};

class FloatComputationInstruction : public FloatInstruction {
public:
    virtual ~FloatComputationInstruction() = default;
    virtual i32 immediate() const override { return 0; }
    bool operator==(FloatComputationInstruction const&) const = default;
    RoundingMode rounding_mode() const { return m_rounding_mode; }
    String format_rounding_mode(DisplayStyle display_style) const;

    FloatComputationInstruction(RoundingMode rounding_mode, FloatWidth width)
        : FloatInstruction(width)
        , m_rounding_mode(rounding_mode)
    {
    }

private:
    RoundingMode m_rounding_mode;
};

class FloatTwoArgumentInstruction : public FloatComputationInstruction {
public:
    bool operator==(FloatTwoArgumentInstruction const&) const = default;
    FloatRegister source_register_1() const { return m_rs1; }
    FloatRegister source_register_2() const { return m_rs2; }

    FloatTwoArgumentInstruction(RoundingMode rounding_mode, FloatWidth width, FloatRegister rs1, FloatRegister rs2)
        : FloatComputationInstruction(rounding_mode, width)
        , m_rs1(rs1)
        , m_rs2(rs2)
    {
    }

private:
    FloatRegister m_rs1;
    FloatRegister m_rs2;
};

class FloatRTypeInstruction : public FloatTwoArgumentInstruction {
public:
    bool operator==(FloatRTypeInstruction const&) const = default;
    FloatRegister destination_register() const { return m_rd; }

    FloatRTypeInstruction(RoundingMode rounding_mode, FloatWidth width, FloatRegister rs1, FloatRegister rs2, FloatRegister rd)
        : FloatTwoArgumentInstruction(rounding_mode, width, rs1, rs2)
        , m_rd(rd)
    {
    }

private:
    FloatRegister m_rd;
};

class FloatArithmeticInstruction : public FloatRTypeInstruction {
public:
    enum class Operation : u8 {
        Add,
        Subtract,
        Multiply,
        Divide,
        Min,
        Max,
        // Always use rs1's value except the sign:
        // Copy sign from rs2.
        SignInject,
        // Copy inverted sign from rs2.
        SignInjectNegate,
        // Xor both signs.
        SignInjectXor,
    };

    virtual ~FloatArithmeticInstruction() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(FloatArithmeticInstruction const&) const = default;
    Operation operation() const { return m_operation; }

    FloatArithmeticInstruction(Operation operation, RoundingMode rounding_mode, FloatWidth width, FloatRegister rs1, FloatRegister rs2, FloatRegister rd)
        : FloatRTypeInstruction(rounding_mode, width, rs1, rs2, rd)
        , m_operation(operation)
    {
    }

private:
    Operation m_operation;
};

class FloatSquareRoot : public FloatComputationInstruction {
public:
    virtual ~FloatSquareRoot() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(FloatSquareRoot const&) const = default;

    FloatSquareRoot(RoundingMode rounding_mode, FloatWidth width, FloatRegister rs, FloatRegister rd)
        : FloatComputationInstruction(rounding_mode, width)
        , m_rs(rs)
        , m_rd(rd)
    {
    }

private:
    FloatRegister m_rs;
    FloatRegister m_rd;
};

class FloatCompare : public FloatTwoArgumentInstruction {
public:
    enum class Operation : u8 {
        Equals,
        LessThan,
        LessThanEquals,
    };

    virtual ~FloatCompare() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(FloatCompare const&) const = default;

    FloatCompare(Operation operation, FloatWidth width, FloatRegister rs1, FloatRegister rs2, Register rd)
        : FloatTwoArgumentInstruction(RoundingMode::DYN, width, rs1, rs2)
        , m_rd(rd)
        , m_operation(operation)
    {
    }

private:
    Register m_rd;
    Operation m_operation;
};

class ConvertFloatAndInteger : public FloatComputationInstruction {
public:
    virtual ~ConvertFloatAndInteger() = default;
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(ConvertFloatAndInteger const&) const = default;
    MemoryAccessMode integer_width() const { return m_integer_width; }
    String integer_width_suffix() const;

    ConvertFloatAndInteger(RoundingMode rounding_mode, MemoryAccessMode integer_width, FloatWidth float_width)
        : FloatComputationInstruction(rounding_mode, float_width)
        , m_integer_width(integer_width)
    {
    }

private:
    MemoryAccessMode m_integer_width;
};

class ConvertFloatToInteger : public ConvertFloatAndInteger {
public:
    virtual ~ConvertFloatToInteger() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(ConvertFloatToInteger const&) const = default;

    ConvertFloatToInteger(RoundingMode rounding_mode, MemoryAccessMode integer_width, FloatWidth float_width, FloatRegister rs, Register rd)
        : ConvertFloatAndInteger(rounding_mode, integer_width, float_width)
        , m_rs(rs)
        , m_rd(rd)
    {
    }

private:
    FloatRegister m_rs;
    Register m_rd;
};

class ConvertIntegerToFloat : public ConvertFloatAndInteger {
public:
    virtual ~ConvertIntegerToFloat() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(ConvertIntegerToFloat const&) const = default;

    ConvertIntegerToFloat(RoundingMode rounding_mode, MemoryAccessMode integer_width, FloatWidth float_width, Register rs, FloatRegister rd)
        : ConvertFloatAndInteger(rounding_mode, integer_width, float_width)
        , m_rs(rs)
        , m_rd(rd)
    {
    }

private:
    Register m_rs;
    FloatRegister m_rd;
};

class ConvertFloat : public FloatComputationInstruction {
public:
    enum class Operation {
        SingleToDouble,
        DoubleToSingle,
    };

    virtual ~ConvertFloat() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(ConvertFloat const&) const = default;

    ConvertFloat(Operation operation, RoundingMode rounding_mode, FloatRegister rs, FloatRegister rd)
        : FloatComputationInstruction(rounding_mode, FloatWidth::Double)
        , m_rs(rs)
        , m_rd(rd)
        , m_operation(operation)
    {
    }

private:
    FloatRegister m_rs;
    FloatRegister m_rd;
    Operation m_operation;
};

class FloatClassify : public FloatInstruction {
public:
    virtual ~FloatClassify() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual i32 immediate() const override { return 0; }
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(FloatClassify const&) const = default;

    FloatClassify(FloatWidth width, FloatRegister rs, Register rd)
        : FloatInstruction(width)
        , m_rs(rs)
        , m_rd(rd)
    {
    }

private:
    FloatRegister m_rs;
    Register m_rd;
};

class MoveFloatToInteger : public FloatInstruction {
public:
    virtual ~MoveFloatToInteger() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual i32 immediate() const override { return 0; }
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(MoveFloatToInteger const&) const = default;

    MoveFloatToInteger(FloatWidth width, FloatRegister rs, Register rd)
        : FloatInstruction(width)
        , m_rs(rs)
        , m_rd(rd)
    {
    }

private:
    FloatRegister m_rs;
    Register m_rd;
};

class MoveIntegerToFloat : public FloatInstruction {
public:
    virtual ~MoveIntegerToFloat() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual i32 immediate() const override { return 0; }
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(MoveIntegerToFloat const&) const = default;

    MoveIntegerToFloat(FloatWidth width, Register rs, FloatRegister rd)
        : FloatInstruction(width)
        , m_rs(rs)
        , m_rd(rd)
    {
    }

private:
    Register m_rs;
    FloatRegister m_rd;
};

class FloatFusedMultiplyAdd : public FloatRTypeInstruction {
public:
    enum class Operation : u8 {
        // (rs1 · rs2) + rs3
        MultiplyAdd,
        // (rs1 · rs2) - rs3
        MultiplySubtract,
        // - (rs1 · rs2) + rs3
        NegatedMultiplyAdd,
        // - (rs1 · rs2) - rs3
        NegatedMultiplySubtract,
    };

    virtual ~FloatFusedMultiplyAdd() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(FloatFusedMultiplyAdd const&) const = default;
    FloatRegister source_register_3() const { return m_rs3; }

    FloatFusedMultiplyAdd(Operation operation, RoundingMode rounding_mode, FloatWidth width, FloatRegister rs1, FloatRegister rs2, FloatRegister rs3, FloatRegister rd)
        : FloatRTypeInstruction(rounding_mode, width, rs1, rs2, rd)
        , m_operation(operation)
        , m_rs3(rs3)
    {
    }

private:
    Operation m_operation;
    FloatRegister m_rs3;
};

class FloatMemoryInstruction : public FloatInstruction {
public:
    virtual ~FloatMemoryInstruction() = default;
    virtual i32 immediate() const override { return m_offset; }
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(FloatMemoryInstruction const&) const = default;
    Register base() const { return m_base; }

    FloatMemoryInstruction(i32 offset, Register base, FloatWidth width)
        : FloatInstruction(width)
        , m_base(base)
        , m_offset(offset)
    {
    }

private:
    Register m_base;
    i32 m_offset;
};

class FloatMemoryLoad : public FloatMemoryInstruction {
public:
    virtual ~FloatMemoryLoad() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(FloatMemoryLoad const&) const = default;
    FloatRegister destination_register() const { return m_rd; }

    FloatMemoryLoad(i32 offset, Register base, FloatWidth width, FloatRegister rd)
        : FloatMemoryInstruction(offset, base, width)
        , m_rd(rd)
    {
    }

private:
    FloatRegister m_rd;
};

class FloatMemoryStore : public FloatMemoryInstruction {
public:
    virtual ~FloatMemoryStore() = default;
    virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
    virtual String mnemonic() const override;
    virtual bool instruction_equals(InstructionImpl const&) const override;
    bool operator==(FloatMemoryStore const&) const = default;
    FloatRegister source_register() const { return m_source; }

    FloatMemoryStore(i32 offset, FloatRegister source, Register base, FloatWidth width)
        : FloatMemoryInstruction(offset, base, width)
        , m_source(source)
    {
    }

private:
    FloatRegister m_source;
};

NonnullOwnPtr<InstructionImpl> parse_op_fp(u32 instruction);
NonnullOwnPtr<InstructionImpl> parse_fma(u32 instruction);
NonnullOwnPtr<InstructionImpl> parse_load_fp(u32 instruction);
NonnullOwnPtr<InstructionImpl> parse_store_fp(u32 instruction);

}