aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
Diffstat (limited to 'backend')
-rw-r--r--backend/include/rcc/CodeGen/MachineBasicBlock.h10
-rw-r--r--backend/include/rcc/CodeGen/MachineBasicBlockAttributes.h208
-rw-r--r--backend/include/rcc/CodeGen/MachineFunction.h10
-rw-r--r--backend/include/rcc/CodeGen/MachineFunctionAttributes.h100
-rw-r--r--backend/include/rcc/CodeGen/MachineIRTypes.h25
-rw-r--r--backend/include/rcc/CodeGen/MachineMemOperand.h18
-rw-r--r--backend/lib/CodeGen/CMakeLists.txt8
-rw-r--r--backend/lib/CodeGen/MachineBasicBlockAttributes.cpp83
-rw-r--r--backend/lib/CodeGen/MachineFunctionAttributes.cpp63
-rw-r--r--backend/lib/CodeGen/MachineFunctionCloner.cpp2
-rw-r--r--backend/lib/CodeGen/MachineIRTypes.cpp9
-rw-r--r--backend/lib/CodeGen/MachineMemOperand.cpp8
-rw-r--r--backend/lib/CodeGen/MachineVerifier.cpp6
-rw-r--r--backend/unittests/CodeGen/CMakeLists.txt15
-rw-r--r--backend/unittests/CodeGen/MachineIRAttributesTest.cpp206
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();
+}