diff options
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineBasicBlock.h | 10 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineBasicBlockAttributes.h | 208 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineFunction.h | 10 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineFunctionAttributes.h | 100 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineIRTypes.h | 25 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineMemOperand.h | 18 | ||||
| -rw-r--r-- | backend/lib/CodeGen/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineBasicBlockAttributes.cpp | 83 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineFunctionAttributes.cpp | 63 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineFunctionCloner.cpp | 2 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineIRTypes.cpp | 9 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineMemOperand.cpp | 8 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineVerifier.cpp | 6 | ||||
| -rw-r--r-- | backend/unittests/CodeGen/CMakeLists.txt | 15 | ||||
| -rw-r--r-- | backend/unittests/CodeGen/MachineIRAttributesTest.cpp | 206 |
15 files changed, 745 insertions, 26 deletions
diff --git a/backend/include/rcc/CodeGen/MachineBasicBlock.h b/backend/include/rcc/CodeGen/MachineBasicBlock.h index ba59160..d82477a 100644 --- a/backend/include/rcc/CodeGen/MachineBasicBlock.h +++ b/backend/include/rcc/CodeGen/MachineBasicBlock.h @@ -3,6 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEBASICBLOCK_H #define RCC_CODEGEN_MACHINEBASICBLOCK_H +#include "rcc/CodeGen/MachineBasicBlockAttributes.h" #include "rcc/CodeGen/MachineIRTypes.h" #include "rcc/CodeGen/Register.h" #include "rcc/CodeGen/StableID.h" @@ -124,6 +125,14 @@ public: return LayoutIndex; } + [[nodiscard]] MachineBasicBlockAttributes &attributes() noexcept { + return Attributes; + } + + [[nodiscard]] const MachineBasicBlockAttributes &attributes() const noexcept { + return Attributes; + } + private: MachineBasicBlock(MachineFunction &OwnerFunction, MachineBlockStableID StableID) : OwnerFunction(&OwnerFunction), StableID(StableID) {} @@ -138,6 +147,7 @@ private: std::vector<MachineBasicBlock *> Predecessors; std::vector<MachineSuccessor> Successors; std::vector<MachineBasicBlockLiveIn> LiveIns; + MachineBasicBlockAttributes Attributes; std::optional<std::uint32_t> DenseNumber; std::optional<std::uint32_t> LayoutIndex; diff --git a/backend/include/rcc/CodeGen/MachineBasicBlockAttributes.h b/backend/include/rcc/CodeGen/MachineBasicBlockAttributes.h new file mode 100644 index 0000000..7b132d2 --- /dev/null +++ b/backend/include/rcc/CodeGen/MachineBasicBlockAttributes.h @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_MACHINEBASICBLOCKATTRIBUTES_H +#define RCC_CODEGEN_MACHINEBASICBLOCKATTRIBUTES_H + +#include "rcc/CodeGen/MachineIRTypes.h" +#include "rcc/Support/Error.h" + +#include <cstdint> +#include <optional> +#include <string> +#include <string_view> + +namespace rcc { + +enum class MachineBasicBlockAttribute : std::uint8_t { + MachineBlockAddressTaken, + IRBlockAddressTaken, + LandingPad, + InlineAsmBrIndirectTarget, + EHFuncletEntry, + EHScopeEntry, + Count, +}; + +[[nodiscard]] std::string_view +getMachineBasicBlockAttributeName(MachineBasicBlockAttribute Attribute) noexcept; + +enum class MachineBasicBlockSectionKind : std::uint8_t { + Numbered, + Exception, + Cold, +}; + +class MachineBasicBlockSectionID final { +public: + constexpr MachineBasicBlockSectionID() noexcept = default; + + [[nodiscard]] static constexpr MachineBasicBlockSectionID + numbered(std::uint32_t Number) noexcept { + return MachineBasicBlockSectionID(MachineBasicBlockSectionKind::Numbered, Number); + } + + [[nodiscard]] static constexpr MachineBasicBlockSectionID exception() noexcept { + return MachineBasicBlockSectionID(MachineBasicBlockSectionKind::Exception, 0); + } + + [[nodiscard]] static constexpr MachineBasicBlockSectionID cold() noexcept { + return MachineBasicBlockSectionID(MachineBasicBlockSectionKind::Cold, 0); + } + + [[nodiscard]] constexpr MachineBasicBlockSectionKind kind() const noexcept { + return Kind; + } + + [[nodiscard]] constexpr std::uint32_t number() const noexcept { + return Number; + } + + [[nodiscard]] constexpr bool isDefault() const noexcept { + return Kind == MachineBasicBlockSectionKind::Numbered && Number == 0; + } + + friend constexpr bool operator==(MachineBasicBlockSectionID Left, + MachineBasicBlockSectionID Right) noexcept = default; + +private: + constexpr MachineBasicBlockSectionID(MachineBasicBlockSectionKind Kind, + std::uint32_t Number) noexcept + : Kind(Kind), Number(Number) {} + + MachineBasicBlockSectionKind Kind = MachineBasicBlockSectionKind::Numbered; + std::uint32_t Number = 0; +}; + +struct MachineBasicBlockProfileID final { + std::uint32_t BaseID = 0; + std::uint32_t CloneID = 0; + + friend constexpr bool operator==(MachineBasicBlockProfileID Left, + MachineBasicBlockProfileID Right) noexcept = default; +}; + +class MachineBasicBlockAttributes final { +public: + MachineBasicBlockAttributes() = default; + + [[nodiscard]] static Expected<MachineBasicBlockAttributes> fromRawFlags(std::uint8_t RawFlags); + + [[nodiscard]] bool has(MachineBasicBlockAttribute Attribute) const noexcept { + if (!isValidAttribute(Attribute)) + return false; + return (Flags & flagFor(Attribute)) != 0; + } + + void set(MachineBasicBlockAttribute Attribute) noexcept { + if (isValidAttribute(Attribute)) + Flags |= flagFor(Attribute); + } + + void clear(MachineBasicBlockAttribute Attribute) noexcept { + if (isValidAttribute(Attribute)) + Flags &= static_cast<std::uint8_t>(~flagFor(Attribute)); + } + + [[nodiscard]] std::uint8_t rawFlags() const noexcept { + return Flags; + } + + [[nodiscard]] std::optional<std::string_view> name() const noexcept { + if (!Name) + return std::nullopt; + return *Name; + } + + [[nodiscard]] Expected<void> setName(std::string NewName); + + void clearName() noexcept { + Name.reset(); + } + + [[nodiscard]] std::optional<std::string_view> irBlockName() const noexcept { + if (!IRBlockName) + return std::nullopt; + return *IRBlockName; + } + + [[nodiscard]] Expected<void> setIRBlockName(std::string NewName); + + void clearIRBlockName() noexcept { + IRBlockName.reset(); + } + + [[nodiscard]] Alignment alignment() const noexcept { + return BlockAlignment; + } + + void setAlignment(Alignment NewAlignment) noexcept { + BlockAlignment = NewAlignment; + } + + void clearAlignment() noexcept { + BlockAlignment = Alignment{}; + } + + [[nodiscard]] MachineBasicBlockSectionID sectionID() const noexcept { + return SectionID; + } + + void setSectionID(MachineBasicBlockSectionID NewSectionID) noexcept { + SectionID = NewSectionID; + } + + [[nodiscard]] const std::optional<MachineBasicBlockProfileID> &profileID() const noexcept { + return ProfileID; + } + + void setProfileID(MachineBasicBlockProfileID NewProfileID) noexcept { + ProfileID = NewProfileID; + } + + void clearProfileID() noexcept { + ProfileID.reset(); + } + + [[nodiscard]] std::uint32_t callFrameSize() const noexcept { + return CallFrameSize; + } + + void setCallFrameSize(std::uint32_t Size) noexcept { + CallFrameSize = Size; + } + + [[nodiscard]] Expected<void> verify() const; + + friend bool operator==(const MachineBasicBlockAttributes &Left, + const MachineBasicBlockAttributes &Right) = default; + +private: + static constexpr std::uint8_t AttributeCount = + static_cast<std::uint8_t>(MachineBasicBlockAttribute::Count); + static_assert(AttributeCount < 8); + + static constexpr std::uint8_t ValidFlags = + static_cast<std::uint8_t>((std::uint8_t{1} << AttributeCount) - 1); + + [[nodiscard]] static constexpr bool + isValidAttribute(MachineBasicBlockAttribute Attribute) noexcept { + return static_cast<std::uint8_t>(Attribute) < AttributeCount; + } + + [[nodiscard]] static constexpr std::uint8_t + flagFor(MachineBasicBlockAttribute Attribute) noexcept { + return static_cast<std::uint8_t>(std::uint8_t{1} << static_cast<std::uint8_t>(Attribute)); + } + + std::uint8_t Flags = 0; + std::optional<std::string> Name; + std::optional<std::string> IRBlockName; + Alignment BlockAlignment; + MachineBasicBlockSectionID SectionID; + std::optional<MachineBasicBlockProfileID> ProfileID; + std::uint32_t CallFrameSize = 0; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_MACHINEBASICBLOCKATTRIBUTES_H diff --git a/backend/include/rcc/CodeGen/MachineFunction.h b/backend/include/rcc/CodeGen/MachineFunction.h index b687573..4ed660d 100644 --- a/backend/include/rcc/CodeGen/MachineFunction.h +++ b/backend/include/rcc/CodeGen/MachineFunction.h @@ -6,6 +6,7 @@ #include "rcc/CodeGen/MachineCompilationStatus.h" #include "rcc/CodeGen/MachineConstantPool.h" #include "rcc/CodeGen/MachineFrameInfo.h" +#include "rcc/CodeGen/MachineFunctionAttributes.h" #include "rcc/CodeGen/MachineFunctionProperties.h" #include "rcc/CodeGen/MachineJumpTableInfo.h" #include "rcc/CodeGen/MachineRegisterInfo.h" @@ -89,6 +90,14 @@ public: return Properties; } + [[nodiscard]] MachineFunctionAttributes &attributes() noexcept { + return Attributes; + } + + [[nodiscard]] const MachineFunctionAttributes &attributes() const noexcept { + return Attributes; + } + [[nodiscard]] const TargetFunctionState &targetState() const noexcept { return TargetState; } @@ -166,6 +175,7 @@ private: MachineConstantPool ConstantPool; MachineJumpTableInfo JumpTables; MachineFunctionProperties Properties; + MachineFunctionAttributes Attributes; TargetFunctionState TargetState; MachineCompilationStatus CompilationStatus; MachineBasicBlock *FirstBlock = nullptr; diff --git a/backend/include/rcc/CodeGen/MachineFunctionAttributes.h b/backend/include/rcc/CodeGen/MachineFunctionAttributes.h new file mode 100644 index 0000000..4344640 --- /dev/null +++ b/backend/include/rcc/CodeGen/MachineFunctionAttributes.h @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_MACHINEFUNCTIONATTRIBUTES_H +#define RCC_CODEGEN_MACHINEFUNCTIONATTRIBUTES_H + +#include "rcc/CodeGen/MachineIRTypes.h" +#include "rcc/Support/Error.h" + +#include <cstdint> +#include <optional> +#include <string_view> + +namespace rcc { + +enum class MachineFunctionAttribute : std::uint8_t { + ExposesReturnsTwice, + HasWinCFI, + HasFakeUses, + CallsEHReturn, + CallsUnwindInit, + HasEHContTarget, + HasEHScopes, + HasEHFunclets, + IsOutlined, + DebugInstrRef, + TracksDebugUserValues, + Count, +}; + +[[nodiscard]] std::string_view +getMachineFunctionAttributeName(MachineFunctionAttribute Attribute) noexcept; + +class MachineFunctionAttributes final { +public: + constexpr MachineFunctionAttributes() noexcept = default; + + [[nodiscard]] static Expected<MachineFunctionAttributes> fromRawFlags(std::uint16_t RawFlags); + + [[nodiscard]] constexpr bool has(MachineFunctionAttribute Attribute) const noexcept { + if (!isValidAttribute(Attribute)) + return false; + return (Flags & flagFor(Attribute)) != 0; + } + + constexpr void set(MachineFunctionAttribute Attribute) noexcept { + if (isValidAttribute(Attribute)) + Flags |= flagFor(Attribute); + } + + constexpr void clear(MachineFunctionAttribute Attribute) noexcept { + if (isValidAttribute(Attribute)) + Flags &= static_cast<std::uint16_t>(~flagFor(Attribute)); + } + + [[nodiscard]] constexpr std::uint16_t rawFlags() const noexcept { + return Flags; + } + + [[nodiscard]] std::optional<Alignment> alignment() const noexcept { + return FunctionAlignment; + } + + void setAlignment(Alignment NewAlignment) noexcept { + FunctionAlignment = NewAlignment; + } + + void clearAlignment() noexcept { + FunctionAlignment.reset(); + } + + [[nodiscard]] Expected<void> verify() const; + + friend bool operator==(const MachineFunctionAttributes &Left, + const MachineFunctionAttributes &Right) = default; + +private: + static constexpr std::uint16_t AttributeCount = + static_cast<std::uint16_t>(MachineFunctionAttribute::Count); + static_assert(AttributeCount < 16); + + static constexpr std::uint16_t ValidFlags = + static_cast<std::uint16_t>((std::uint16_t{1} << AttributeCount) - 1); + + [[nodiscard]] static constexpr bool + isValidAttribute(MachineFunctionAttribute Attribute) noexcept { + return static_cast<std::uint16_t>(Attribute) < AttributeCount; + } + + [[nodiscard]] static constexpr std::uint16_t + flagFor(MachineFunctionAttribute Attribute) noexcept { + return static_cast<std::uint16_t>(std::uint16_t{1} << static_cast<std::uint16_t>(Attribute)); + } + + std::uint16_t Flags = 0; + std::optional<Alignment> FunctionAlignment; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_MACHINEFUNCTIONATTRIBUTES_H diff --git a/backend/include/rcc/CodeGen/MachineIRTypes.h b/backend/include/rcc/CodeGen/MachineIRTypes.h index 8906bbe..90aa2b7 100644 --- a/backend/include/rcc/CodeGen/MachineIRTypes.h +++ b/backend/include/rcc/CodeGen/MachineIRTypes.h @@ -83,6 +83,24 @@ using TargetConstantTypeID = MachineIndex<detail::TargetConstantTypeIDTag, std:: using TargetFunctionStateTypeID = MachineIndex<detail::TargetFunctionStateTypeIDTag, std::uint64_t>; using TargetRelocationKindID = MachineIndex<detail::TargetRelocationKindIDTag>; +class Alignment final { +public: + constexpr Alignment() noexcept = default; + + [[nodiscard]] static Expected<Alignment> create(std::uint64_t Bytes); + + [[nodiscard]] constexpr std::uint64_t bytes() const noexcept { + return Bytes; + } + + friend constexpr bool operator==(Alignment Left, Alignment Right) noexcept = default; + +private: + explicit constexpr Alignment(std::uint64_t Bytes) noexcept : Bytes(Bytes) {} + + std::uint64_t Bytes = 1; +}; + class Opcode final { public: constexpr Opcode() noexcept = default; @@ -215,6 +233,12 @@ enum class MachineInstrFlag : std::uint8_t { BundledWithSucc, NoMerge, Unpredictable, + NoConvergent, + NonNeg, + Disjoint, + NoUSWrap, + SameSign, + InBounds, Count, }; @@ -268,6 +292,7 @@ struct SourceLocation final { }; static_assert(sizeof(Opcode) == sizeof(std::uint32_t)); +static_assert(sizeof(Alignment) == sizeof(std::uint64_t)); static_assert(sizeof(FrameIndex) == sizeof(std::uint32_t)); static_assert(sizeof(MemoryAliasSourceID) == sizeof(std::uint64_t)); static_assert(std::is_trivially_copyable_v<Opcode>); diff --git a/backend/include/rcc/CodeGen/MachineMemOperand.h b/backend/include/rcc/CodeGen/MachineMemOperand.h index e513385..3f1fc64 100644 --- a/backend/include/rcc/CodeGen/MachineMemOperand.h +++ b/backend/include/rcc/CodeGen/MachineMemOperand.h @@ -80,24 +80,6 @@ enum class AtomicOrdering : std::uint8_t { SequentiallyConsistent, }; -class Alignment final { -public: - constexpr Alignment() noexcept = default; - - [[nodiscard]] static Expected<Alignment> create(std::uint64_t Bytes); - - [[nodiscard]] constexpr std::uint64_t bytes() const noexcept { - return Bytes; - } - - friend constexpr bool operator==(Alignment Left, Alignment Right) noexcept = default; - -private: - explicit constexpr Alignment(std::uint64_t Bytes) noexcept : Bytes(Bytes) {} - - std::uint64_t Bytes = 1; -}; - class MemorySize final { public: enum class Kind : std::uint8_t { diff --git a/backend/lib/CodeGen/CMakeLists.txt b/backend/lib/CodeGen/CMakeLists.txt index 2c4f6f8..35e9a23 100644 --- a/backend/lib/CodeGen/CMakeLists.txt +++ b/backend/lib/CodeGen/CMakeLists.txt @@ -5,12 +5,14 @@ set( CompilationUnit.cpp InstructionDescriptor.cpp LowLevelType.cpp + MachineBasicBlockAttributes.cpp MachineCompilationStatus.cpp MachineBasicBlock.cpp MachineCFGUpdater.cpp MachineConstantPool.cpp MachineFrameInfo.cpp MachineFunction.cpp + MachineFunctionAttributes.cpp MachineFunctionCloner.cpp MachineIRTypes.cpp MachineIRBuilder.cpp @@ -33,12 +35,14 @@ set( "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/CompilationUnit.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/InstructionDescriptor.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/LowLevelType.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineBasicBlockAttributes.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineCompilationStatus.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineBasicBlock.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineCFGUpdater.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineConstantPool.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineFrameInfo.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineFunction.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineFunctionAttributes.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineFunctionCloner.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineIRTypes.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineIRBuilder.h" @@ -90,12 +94,14 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/CompilationUnit.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/InstructionDescriptor.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/LowLevelType.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachineBasicBlockAttributes.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineCompilationStatus.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineBasicBlock.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineCFGUpdater.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineConstantPool.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFrameInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunction.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunctionAttributes.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunctionCloner.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRTypes.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRBuilder.cpp" @@ -118,12 +124,14 @@ rcc_backend_register_tidy_files( "${CMAKE_CURRENT_SOURCE_DIR}/CompilationUnit.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/InstructionDescriptor.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/LowLevelType.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachineBasicBlockAttributes.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineCompilationStatus.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineBasicBlock.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineCFGUpdater.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineConstantPool.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFrameInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunction.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunctionAttributes.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunctionCloner.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRTypes.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRBuilder.cpp" diff --git a/backend/lib/CodeGen/MachineBasicBlockAttributes.cpp b/backend/lib/CodeGen/MachineBasicBlockAttributes.cpp new file mode 100644 index 0000000..8cb6d48 --- /dev/null +++ b/backend/lib/CodeGen/MachineBasicBlockAttributes.cpp @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/CodeGen/MachineBasicBlockAttributes.h" + +#include <cstdint> +#include <string> +#include <string_view> +#include <utility> + +namespace rcc { + +std::string_view getMachineBasicBlockAttributeName(MachineBasicBlockAttribute Attribute) noexcept { + switch (Attribute) { + case MachineBasicBlockAttribute::MachineBlockAddressTaken: + return "MachineBlockAddressTaken"; + case MachineBasicBlockAttribute::IRBlockAddressTaken: + return "IRBlockAddressTaken"; + case MachineBasicBlockAttribute::LandingPad: + return "LandingPad"; + case MachineBasicBlockAttribute::InlineAsmBrIndirectTarget: + return "InlineAsmBrIndirectTarget"; + case MachineBasicBlockAttribute::EHFuncletEntry: + return "EHFuncletEntry"; + case MachineBasicBlockAttribute::EHScopeEntry: + return "EHScopeEntry"; + case MachineBasicBlockAttribute::Count: + return "Invalid"; + } + return "Invalid"; +} + +Expected<MachineBasicBlockAttributes> +MachineBasicBlockAttributes::fromRawFlags(std::uint8_t RawFlags) { + if ((RawFlags & static_cast<std::uint8_t>(~ValidFlags)) != 0) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine basic block attributes contain unknown flag bits"); + } + MachineBasicBlockAttributes Result; + Result.Flags = RawFlags; + return Result; +} + +Expected<void> MachineBasicBlockAttributes::setName(std::string NewName) { + if (NewName.empty()) { + return makeUnexpected(ErrorCode::InvalidArgument, "machine basic block name cannot be empty"); + } + Name = std::move(NewName); + return {}; +} + +Expected<void> MachineBasicBlockAttributes::setIRBlockName(std::string NewName) { + if (NewName.empty()) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine basic block IR name cannot be empty"); + } + IRBlockName = std::move(NewName); + return {}; +} + +Expected<void> MachineBasicBlockAttributes::verify() const { + if ((Flags & static_cast<std::uint8_t>(~ValidFlags)) != 0) { + return makeUnexpected(ErrorCode::VerificationError, + "machine basic block attributes contain unknown flag bits"); + } + if (Name && Name->empty()) { + return makeUnexpected(ErrorCode::VerificationError, "machine basic block name cannot be empty"); + } + if (IRBlockName && IRBlockName->empty()) { + return makeUnexpected(ErrorCode::VerificationError, + "machine basic block IR name cannot be empty"); + } + if (has(MachineBasicBlockAttribute::IRBlockAddressTaken) && !IRBlockName) { + return makeUnexpected(ErrorCode::VerificationError, + "IR-block-address-taken block requires an IR block reference"); + } + if (BlockAlignment.bytes() == 0) { + return makeUnexpected(ErrorCode::VerificationError, + "machine basic block alignment must be nonzero"); + } + return {}; +} + +} // namespace rcc diff --git a/backend/lib/CodeGen/MachineFunctionAttributes.cpp b/backend/lib/CodeGen/MachineFunctionAttributes.cpp new file mode 100644 index 0000000..799e701 --- /dev/null +++ b/backend/lib/CodeGen/MachineFunctionAttributes.cpp @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/CodeGen/MachineFunctionAttributes.h" + +#include <cstdint> +#include <string_view> + +namespace rcc { + +std::string_view getMachineFunctionAttributeName(MachineFunctionAttribute Attribute) noexcept { + switch (Attribute) { + case MachineFunctionAttribute::ExposesReturnsTwice: + return "ExposesReturnsTwice"; + case MachineFunctionAttribute::HasWinCFI: + return "HasWinCFI"; + case MachineFunctionAttribute::HasFakeUses: + return "HasFakeUses"; + case MachineFunctionAttribute::CallsEHReturn: + return "CallsEHReturn"; + case MachineFunctionAttribute::CallsUnwindInit: + return "CallsUnwindInit"; + case MachineFunctionAttribute::HasEHContTarget: + return "HasEHContTarget"; + case MachineFunctionAttribute::HasEHScopes: + return "HasEHScopes"; + case MachineFunctionAttribute::HasEHFunclets: + return "HasEHFunclets"; + case MachineFunctionAttribute::IsOutlined: + return "IsOutlined"; + case MachineFunctionAttribute::DebugInstrRef: + return "DebugInstrRef"; + case MachineFunctionAttribute::TracksDebugUserValues: + return "TracksDebugUserValues"; + case MachineFunctionAttribute::Count: + return "Invalid"; + } + return "Invalid"; +} + +Expected<MachineFunctionAttributes> +MachineFunctionAttributes::fromRawFlags(std::uint16_t RawFlags) { + if ((RawFlags & static_cast<std::uint16_t>(~ValidFlags)) != 0) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine function attributes contain unknown flag bits"); + } + MachineFunctionAttributes Result; + Result.Flags = RawFlags; + return Result; +} + +Expected<void> MachineFunctionAttributes::verify() const { + if ((Flags & static_cast<std::uint16_t>(~ValidFlags)) != 0) { + return makeUnexpected(ErrorCode::VerificationError, + "machine function attributes contain unknown flag bits"); + } + if (FunctionAlignment && FunctionAlignment->bytes() == 0) { + return makeUnexpected(ErrorCode::VerificationError, + "machine function alignment must be nonzero"); + } + return {}; +} + +} // namespace rcc diff --git a/backend/lib/CodeGen/MachineFunctionCloner.cpp b/backend/lib/CodeGen/MachineFunctionCloner.cpp index d365fd0..971ef3c 100644 --- a/backend/lib/CodeGen/MachineFunctionCloner.cpp +++ b/backend/lib/CodeGen/MachineFunctionCloner.cpp @@ -290,6 +290,7 @@ cloneMemOperand(const MachineMemOperand &SourceOperand, CloneState &State) { auto AppendResult = State.Destination.appendBlock(**DestinationBlock); if (!AppendResult) return std::unexpected(AppendResult.error()); + (*DestinationBlock)->attributes() = SourceBlock->attributes(); State.Blocks.emplace(SourceBlock, *DestinationBlock); State.Result.BlockStableIDs.emplace(SourceBlock->stableID(), (*DestinationBlock)->stableID()); @@ -616,6 +617,7 @@ Expected<MachineFunctionCloneResult> cloneMachineFunction(const MachineFunction return std::unexpected(CompilationStatus.error()); Result.ClonedFunction->compilationStatus() = std::move(*CompilationStatus); Result.ClonedFunction->properties() = Source.properties(); + Result.ClonedFunction->attributes() = Source.attributes(); auto DestinationVerification = MachineVerifier::verify(*Result.ClonedFunction, Target); if (!DestinationVerification) return std::unexpected(DestinationVerification.error()); diff --git a/backend/lib/CodeGen/MachineIRTypes.cpp b/backend/lib/CodeGen/MachineIRTypes.cpp index 7f97e98..b5348b3 100644 --- a/backend/lib/CodeGen/MachineIRTypes.cpp +++ b/backend/lib/CodeGen/MachineIRTypes.cpp @@ -2,8 +2,17 @@ #include "rcc/CodeGen/MachineIRTypes.h" +#include <bit> + namespace rcc { +Expected<Alignment> Alignment::create(std::uint64_t Bytes) { + if (!std::has_single_bit(Bytes)) { + return makeUnexpected(ErrorCode::InvalidArgument, "alignment must be a nonzero power of two"); + } + return Alignment(Bytes); +} + Expected<BranchProbability> BranchProbability::fromFraction(std::uint32_t Numerator, std::uint32_t Denominator) { if (Denominator == 0) { diff --git a/backend/lib/CodeGen/MachineMemOperand.cpp b/backend/lib/CodeGen/MachineMemOperand.cpp index 76aabd1..451dbdb 100644 --- a/backend/lib/CodeGen/MachineMemOperand.cpp +++ b/backend/lib/CodeGen/MachineMemOperand.cpp @@ -2,7 +2,6 @@ #include "rcc/CodeGen/MachineMemOperand.h" -#include <bit> #include <utility> namespace rcc { @@ -119,13 +118,6 @@ MemoryAccessFlags::MemoryAccessFlags(std::initializer_list<MemoryAccessFlag> Fla set(Flag); } -Expected<Alignment> Alignment::create(std::uint64_t Bytes) { - if (!std::has_single_bit(Bytes)) { - return makeUnexpected(ErrorCode::InvalidArgument, "alignment must be a nonzero power of two"); - } - return Alignment(Bytes); -} - Expected<MemorySize> MemorySize::fixed(std::uint64_t Bytes) { if (Bytes == 0) return makeUnexpected(ErrorCode::InvalidArgument, "fixed memory size must be nonzero"); diff --git a/backend/lib/CodeGen/MachineVerifier.cpp b/backend/lib/CodeGen/MachineVerifier.cpp index b507079..905d685 100644 --- a/backend/lib/CodeGen/MachineVerifier.cpp +++ b/backend/lib/CodeGen/MachineVerifier.cpp @@ -34,6 +34,9 @@ public: if (Function.name().empty() || !Function.stableID().isValid()) return fail("function identity is invalid"); + auto AttributeResult = Function.attributes().verify(); + if (!AttributeResult) + return failWith("function attributes", AttributeResult.error()); if (Function.targetState().hasValue()) { auto TargetStateResult = Function.targetState().verify(); if (!TargetStateResult) @@ -134,6 +137,9 @@ private: if (!Block->stableID().isValid() || !BlockIDs.insert(Block->stableID()).second) { return fail("arena block registry contains an invalid or duplicate StableID"); } + auto AttributeResult = Block->attributes().verify(); + if (!AttributeResult) + return failWith("basic block attributes", AttributeResult.error()); } std::unordered_set<MachineInstrStableID> InstructionIDs; diff --git a/backend/unittests/CodeGen/CMakeLists.txt b/backend/unittests/CodeGen/CMakeLists.txt index e128d0b..ff38ed7 100644 --- a/backend/unittests/CodeGen/CMakeLists.txt +++ b/backend/unittests/CodeGen/CMakeLists.txt @@ -9,6 +9,7 @@ set( MachineConstantPoolTest.cpp MachineFrameInfoTest.cpp MachineFunctionClonerTest.cpp + MachineIRAttributesTest.cpp MachineIRBuilderTest.cpp MachineIRCoreTest.cpp MachineJumpTableInfoTest.cpp @@ -110,6 +111,18 @@ add_test( COMMAND RCCBackendCodeGenMachineIRBuilderTests ) +add_executable(RCCBackendCodeGenMachineIRAttributesTests MachineIRAttributesTest.cpp) +rcc_backend_configure_target(RCCBackendCodeGenMachineIRAttributesTests) +target_link_libraries( + RCCBackendCodeGenMachineIRAttributesTests + PRIVATE RCCBackend::CodeGen RCCBackend::TestTarget +) + +add_test( + NAME RCCBackend.CodeGen.MachineIRAttributes + COMMAND RCCBackendCodeGenMachineIRAttributesTests +) + add_executable(RCCBackendCodeGenMachineVerifierTests MachineVerifierTest.cpp) rcc_backend_configure_target(RCCBackendCodeGenMachineVerifierTests) target_link_libraries( @@ -205,6 +218,7 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/MachineConstantPoolTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFrameInfoTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunctionClonerTest.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRAttributesTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRBuilderTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRCoreTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineJumpTableInfoTest.cpp" @@ -223,6 +237,7 @@ rcc_backend_register_tidy_files( "${CMAKE_CURRENT_SOURCE_DIR}/MachineConstantPoolTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFrameInfoTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunctionClonerTest.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRAttributesTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRBuilderTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRCoreTest.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineJumpTableInfoTest.cpp" diff --git a/backend/unittests/CodeGen/MachineIRAttributesTest.cpp b/backend/unittests/CodeGen/MachineIRAttributesTest.cpp new file mode 100644 index 0000000..5619210 --- /dev/null +++ b/backend/unittests/CodeGen/MachineIRAttributesTest.cpp @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "Target/TestTarget.h" +#include "rcc/CodeGen/InstructionDescriptor.h" +#include "rcc/CodeGen/MachineBasicBlock.h" +#include "rcc/CodeGen/MachineBasicBlockAttributes.h" +#include "rcc/CodeGen/MachineFunction.h" +#include "rcc/CodeGen/MachineFunctionAttributes.h" +#include "rcc/CodeGen/MachineFunctionCloner.h" +#include "rcc/CodeGen/MachineIRTypes.h" +#include "rcc/CodeGen/MachineInstr.h" +#include "rcc/CodeGen/MachineVerifier.h" +#include "rcc/CodeGen/TargetDescription.h" + +#include <cstdint> +#include <iostream> +#include <memory> +#include <string> +#include <string_view> +#include <utility> +#include <vector> + +namespace { + +constexpr std::uint32_t NopOpcode = 1; + +class TestContext final { +public: + void expect(bool Condition, std::string_view Message) { + if (Condition) + return; + std::cerr << Message << '\n'; + ++FailureCount; + } + + [[nodiscard]] int result() const noexcept { + return FailureCount == 0 ? 0 : 1; + } + +private: + int FailureCount = 0; +}; + +[[nodiscard]] rcc::Expected<rcc::TargetDescription> createTarget() { + rcc::InstructionDescriptor Nop; + Nop.InstructionOpcode = rcc::Opcode::fromValue(NopOpcode); + Nop.Name = "TEST_NOP"; + Nop.Flags = {rcc::InstructionFlag::ProducesCode}; + + std::vector<rcc::InstructionDescriptor> Descriptors; + Descriptors.push_back(std::move(Nop)); + auto Instructions = rcc::InstructionSet::create(std::move(Descriptors)); + if (!Instructions) + return std::unexpected(Instructions.error()); + return rcc::test::createTestTargetDescription(std::move(*Instructions)); +} + +[[nodiscard]] std::unique_ptr<rcc::MachineFunction> createFunction(TestContext &Context, + std::uint64_t StableID) { + auto Function = + rcc::MachineFunction::create("attributes", rcc::MachineFunctionStableID::fromValue(StableID)); + Context.expect(Function.has_value(), "machine function creation must succeed"); + if (!Function) + return nullptr; + return std::move(*Function); +} + +void testAttributeValueTypes(TestContext &Context) { + rcc::MachineFunctionAttributes FunctionAttributes; + FunctionAttributes.set(rcc::MachineFunctionAttribute::ExposesReturnsTwice); + FunctionAttributes.set(rcc::MachineFunctionAttribute::TracksDebugUserValues); + Context.expect(FunctionAttributes.has(rcc::MachineFunctionAttribute::ExposesReturnsTwice) && + FunctionAttributes.has(rcc::MachineFunctionAttribute::TracksDebugUserValues) && + rcc::getMachineFunctionAttributeName( + rcc::MachineFunctionAttribute::TracksDebugUserValues) == + "TracksDebugUserValues", + "function attribute flags and names must be stable"); + + auto DecodedFunctionAttributes = + rcc::MachineFunctionAttributes::fromRawFlags(FunctionAttributes.rawFlags()); + Context.expect(DecodedFunctionAttributes.has_value() && + DecodedFunctionAttributes->rawFlags() == FunctionAttributes.rawFlags(), + "function attribute raw flags must round trip"); + Context.expect(!rcc::MachineFunctionAttributes::fromRawFlags(std::uint16_t{1} << 15U), + "unknown function attribute bits must be rejected"); + + rcc::MachineBasicBlockAttributes BlockAttributes; + Context.expect(!BlockAttributes.setName("") && !BlockAttributes.setIRBlockName(""), + "empty block and IR block names must be rejected"); + Context.expect(BlockAttributes.setName("entry").has_value() && + BlockAttributes.setIRBlockName("entry").has_value(), + "decoded block and IR block names must be accepted"); + BlockAttributes.set(rcc::MachineBasicBlockAttribute::IRBlockAddressTaken); + BlockAttributes.setCallFrameSize(0); + Context.expect(BlockAttributes.verify().has_value() && BlockAttributes.callFrameSize() == 0, + "zero call-frame size must be the semantic default"); + BlockAttributes.setSectionID(rcc::MachineBasicBlockSectionID::exception()); + BlockAttributes.setProfileID({.BaseID = 7, .CloneID = 2}); + Context.expect( + BlockAttributes.sectionID().kind() == rcc::MachineBasicBlockSectionKind::Exception && + BlockAttributes.sectionID().number() == 0 && + BlockAttributes.profileID() == rcc::MachineBasicBlockProfileID{.BaseID = 7, .CloneID = 2}, + "special section and fixed profile identities must remain structured"); + Context.expect(!rcc::MachineBasicBlockAttributes::fromRawFlags(std::uint8_t{1} << 7U), + "unknown block attribute bits must be rejected"); + + rcc::MachineInstrFlags Flags{ + rcc::MachineInstrFlag::NoConvergent, rcc::MachineInstrFlag::NonNeg, + rcc::MachineInstrFlag::Disjoint, rcc::MachineInstrFlag::NoUSWrap, + rcc::MachineInstrFlag::SameSign, rcc::MachineInstrFlag::InBounds, + }; + Context.expect( + Flags.has(rcc::MachineInstrFlag::NoConvergent) && Flags.has(rcc::MachineInstrFlag::NonNeg) && + Flags.has(rcc::MachineInstrFlag::Disjoint) && + Flags.has(rcc::MachineInstrFlag::NoUSWrap) && + Flags.has(rcc::MachineInstrFlag::SameSign) && Flags.has(rcc::MachineInstrFlag::InBounds), + "all fixed MIR instruction flags must have independent storage"); +} + +void testVerifierAndClone(TestContext &Context) { + auto Target = createTarget(); + auto Function = createFunction(Context, 1); + if (!Target || Function == nullptr) + return; + + auto FunctionAlignment = rcc::Alignment::create(32); + auto BlockAlignment = rcc::Alignment::create(16); + Context.expect(FunctionAlignment.has_value() && BlockAlignment.has_value(), + "power-of-two alignments must be accepted"); + if (!FunctionAlignment || !BlockAlignment) + return; + + Function->attributes().set(rcc::MachineFunctionAttribute::ExposesReturnsTwice); + Function->attributes().set(rcc::MachineFunctionAttribute::HasEHScopes); + Function->attributes().set(rcc::MachineFunctionAttribute::DebugInstrRef); + Function->attributes().setAlignment(*FunctionAlignment); + + auto BlockResult = Function->createBasicBlock(); + Context.expect(BlockResult.has_value(), "machine basic block creation must succeed"); + if (!BlockResult) + return; + rcc::MachineBasicBlock *Block = *BlockResult; + Context.expect(Function->appendBlock(*Block).has_value(), + "machine basic block linking must succeed"); + Context.expect(Block->attributes().setName("entry").has_value(), + "machine basic block name must be stored"); + Block->attributes().set(rcc::MachineBasicBlockAttribute::IRBlockAddressTaken); + Context.expect(!rcc::MachineVerifier::verify(*Function, *Target), + "IR-block-address-taken must require an IR block association"); + + Context.expect(Block->attributes().setIRBlockName("entry").has_value(), + "IR block association must be stored"); + Block->attributes().set(rcc::MachineBasicBlockAttribute::LandingPad); + Block->attributes().setAlignment(*BlockAlignment); + Block->attributes().setSectionID(rcc::MachineBasicBlockSectionID::numbered(3)); + Block->attributes().setProfileID({.BaseID = 11, .CloneID = 4}); + Block->attributes().setCallFrameSize(64); + + auto InstructionResult = Function->createInstruction(rcc::Opcode::fromValue(NopOpcode)); + Context.expect(InstructionResult.has_value(), "machine instruction creation must succeed"); + if (!InstructionResult) + return; + rcc::MachineInstr *Instruction = *InstructionResult; + Instruction->setFlags({ + rcc::MachineInstrFlag::NoConvergent, + rcc::MachineInstrFlag::NonNeg, + rcc::MachineInstrFlag::Disjoint, + rcc::MachineInstrFlag::NoUSWrap, + rcc::MachineInstrFlag::SameSign, + rcc::MachineInstrFlag::InBounds, + }); + Context.expect(Block->appendInstruction(*Instruction).has_value(), + "machine instruction linking must succeed"); + Context.expect(rcc::MachineVerifier::verify(*Function, *Target).has_value(), + "function and block MIR attributes must pass the unified verifier"); + + auto Clone = + rcc::cloneMachineFunction(*Function, *Target, + rcc::MachineFunctionCloneOptions{ + .NewStableID = rcc::MachineFunctionStableID::fromValue(2), + .NewName = std::string("attributes.clone"), + }); + Context.expect(Clone.has_value(), "attributed machine function clone must succeed"); + if (!Clone) + return; + + const rcc::MachineFunction &ClonedFunction = *Clone->ClonedFunction; + const rcc::MachineBasicBlock *ClonedBlock = ClonedFunction.firstBlock(); + const rcc::MachineInstr *ClonedInstruction = + ClonedBlock == nullptr ? nullptr : ClonedBlock->firstInstruction(); + Context.expect(ClonedFunction.attributes() == Function->attributes(), + "function MIR attributes must survive deep cloning"); + Context.expect(ClonedBlock != nullptr && ClonedBlock->attributes() == Block->attributes(), + "basic block MIR attributes must survive deep cloning"); + Context.expect(ClonedInstruction != nullptr && ClonedInstruction->flags() == Instruction->flags(), + "complete MIR instruction flags must survive deep cloning"); +} + +} // namespace + +int main() { + TestContext Context; + testAttributeValueTypes(Context); + testVerifierAndClone(Context); + return Context.result(); +} |
