aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Target/RISCV
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib/Target/RISCV')
-rw-r--r--backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp218
1 files changed, 43 insertions, 175 deletions
diff --git a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
index 0db51f0..78c56a3 100644
--- a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
+++ b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp
@@ -2,7 +2,6 @@
#include "rcc/Target/RISCV/RISCVMCTargetLowering.h"
-#include "rcc/CodeGen/GenericConstant.h"
#include "rcc/CodeGen/GenericOpcodes.h"
#include "rcc/CodeGen/GlobalObject.h"
#include "rcc/CodeGen/InstructionDescriptor.h"
@@ -15,6 +14,8 @@
#include "rcc/CodeGen/MachineOperand.h"
#include "rcc/CodeGen/Register.h"
#include "rcc/CodeGen/TargetConstant.h"
+#include "rcc/IR/Constants.h"
+#include "rcc/IR/DataLayout.h"
#include "rcc/MC/MCContext.h"
#include "rcc/MC/MCExpr.h"
#include "rcc/MC/MCInst.h"
@@ -51,11 +52,6 @@ constexpr std::uint32_t KnownTargetFlags =
CallTargetFlag | PCRelativeHighTargetFlag | PCRelativeLowTargetFlag | CopyF32TargetFlag |
CopyF64TargetFlag | AbsoluteHighTargetFlag | AbsoluteLowTargetFlag;
-struct TypeLayout final {
- std::uint64_t Size = 0;
- std::uint64_t Alignment = 1;
-};
-
[[nodiscard]] Expected<std::uint8_t> targetRelocationSize(TargetRelocationKindID Kind) {
if (Kind == targetRelocationKind(RISCVTargetRelocationKind::Absolute32))
return 4;
@@ -65,132 +61,6 @@ struct TypeLayout final {
"RV64GC target constant has an unknown relocation kind");
}
-[[nodiscard]] Expected<std::uint64_t> checkedAdd(std::uint64_t Left, std::uint64_t Right) {
- std::uint64_t Result = 0;
- if (__builtin_add_overflow(Left, Right, &Result))
- return makeUnexpected(ErrorCode::AssemblyLoweringFailed, "constant layout size overflows");
- return Result;
-}
-
-[[nodiscard]] Expected<std::uint64_t> checkedMultiply(std::uint64_t Left, std::uint64_t Right) {
- std::uint64_t Result = 0;
- if (__builtin_mul_overflow(Left, Right, &Result))
- return makeUnexpected(ErrorCode::AssemblyLoweringFailed, "constant layout size overflows");
- return Result;
-}
-
-[[nodiscard]] Expected<std::uint64_t> alignTo(std::uint64_t Value, std::uint64_t Alignment) {
- if (Alignment == 0 || (Alignment & (Alignment - 1U)) != 0) {
- return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
- "constant layout requires power-of-two alignment");
- }
- auto Adjusted = checkedAdd(Value, Alignment - 1U);
- if (!Adjusted)
- return std::unexpected(Adjusted.error());
- return *Adjusted & ~(Alignment - 1U);
-}
-
-[[nodiscard]] std::uint64_t naturalAlignment(std::uint64_t Size) noexcept {
- if (Size <= 1)
- return 1;
- std::uint64_t Result = 1;
- while (Result < Size && Result < 16)
- Result <<= 1U;
- return Result;
-}
-
-[[nodiscard]] const GenericConstantType &resolvedType(const GenericConstantType &Type) noexcept {
- const GenericConstantType *Result = &Type;
- std::size_t Depth = 0;
- while (Result->Kind == GenericConstantTypeKind::Named && Result->Elements.size() == 1 &&
- Depth++ < 1024) {
- Result = &Result->Elements.front();
- }
- return *Result;
-}
-
-[[nodiscard]] Expected<TypeLayout> layoutType(const GenericConstantType &InputType,
- std::size_t Depth = 0) {
- if (Depth > 1024) {
- return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
- "constant layout exceeds its nesting limit");
- }
- const GenericConstantType &Type = resolvedType(InputType);
- switch (Type.Kind) {
- case GenericConstantTypeKind::Integer: {
- const std::uint64_t Size = (static_cast<std::uint64_t>(Type.BitWidth) + 7U) / 8U;
- return TypeLayout{.Size = Size, .Alignment = naturalAlignment(Size)};
- }
- case GenericConstantTypeKind::Byte:
- return TypeLayout{.Size = 1, .Alignment = 1};
- case GenericConstantTypeKind::Floating: {
- const auto BitWidth = getFloatSemanticsBitWidth(Type.Semantics);
- if (!BitWidth) {
- return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
- "floating constant has unknown semantics");
- }
- const std::uint64_t Size = (static_cast<std::uint64_t>(*BitWidth) + 7U) / 8U;
- return TypeLayout{.Size = Size, .Alignment = naturalAlignment(Size)};
- }
- case GenericConstantTypeKind::Pointer:
- return TypeLayout{.Size = 8, .Alignment = 8};
- case GenericConstantTypeKind::Array:
- case GenericConstantTypeKind::Vector: {
- if (Type.Elements.size() != 1 ||
- (Type.Kind == GenericConstantTypeKind::Vector && Type.Scalable)) {
- return makeUnexpected(ErrorCode::Unsupported,
- "RV64GC assembly cannot lay out this sequential constant type");
- }
- auto Element = layoutType(Type.Elements.front(), Depth + 1);
- if (!Element)
- return std::unexpected(Element.error());
- auto Stride = alignTo(Element->Size, Element->Alignment);
- if (!Stride)
- return std::unexpected(Stride.error());
- auto Size = checkedMultiply(*Stride, Type.ElementCount);
- if (!Size)
- return std::unexpected(Size.error());
- std::uint64_t Alignment = Element->Alignment;
- if (Type.Kind == GenericConstantTypeKind::Vector)
- Alignment = naturalAlignment(*Size);
- return TypeLayout{.Size = *Size, .Alignment = Alignment};
- }
- case GenericConstantTypeKind::Struct: {
- std::uint64_t Offset = 0;
- std::uint64_t StructAlignment = 1;
- for (const GenericConstantType &ElementType : Type.Elements) {
- auto Element = layoutType(ElementType, Depth + 1);
- if (!Element)
- return std::unexpected(Element.error());
- const std::uint64_t ElementAlignment = Type.Packed ? 1 : Element->Alignment;
- auto Aligned = alignTo(Offset, ElementAlignment);
- if (!Aligned)
- return std::unexpected(Aligned.error());
- auto End = checkedAdd(*Aligned, Element->Size);
- if (!End)
- return std::unexpected(End.error());
- Offset = *End;
- StructAlignment = std::max(StructAlignment, ElementAlignment);
- }
- auto Size = alignTo(Offset, StructAlignment);
- if (!Size)
- return std::unexpected(Size.error());
- return TypeLayout{.Size = *Size, .Alignment = StructAlignment};
- }
- case GenericConstantTypeKind::Named:
- return makeUnexpected(ErrorCode::Unsupported,
- "RV64GC assembly cannot lay out an unresolved named constant type");
- case GenericConstantTypeKind::Invalid:
- case GenericConstantTypeKind::Void:
- case GenericConstantTypeKind::Label:
- case GenericConstantTypeKind::Token:
- case GenericConstantTypeKind::Metadata:
- case GenericConstantTypeKind::Function:
- return makeUnexpected(ErrorCode::AssemblyLoweringFailed, "constant has a non-storage type");
- }
- return makeUnexpected(ErrorCode::InternalError, "generic constant type kind is invalid");
-}
-
[[nodiscard]] Expected<mc::MCExprRef> addOffset(mc::MCExprRef Expression, std::int64_t Offset) {
if (Offset == 0)
return Expression;
@@ -509,11 +379,10 @@ struct TypeLayout final {
return Size == 0 ? Expected<void>{} : Streamer.emitZeroFill(Size);
}
-[[nodiscard]] Expected<void> emitGenericConstantImpl(const GenericConstantData &Constant,
- const TypeLayout &Layout,
- MachineMCContext &Context,
- mc::MCStreamer &Streamer,
- std::size_t Depth = 0) {
+[[nodiscard]] Expected<void>
+emitGenericConstantImpl(const GenericConstantData &Constant, const DataLayout &Layout,
+ std::uint64_t AllocationSize, MachineMCContext &Context,
+ mc::MCStreamer &Streamer, std::size_t Depth = 0) {
if (Depth > 1024) {
return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
"generic constant exceeds its emission nesting limit");
@@ -522,17 +391,17 @@ struct TypeLayout final {
case GenericConstantKind::Integer: {
if (!Constant.IntegerValue)
return makeUnexpected(ErrorCode::InternalError, "integer constant has no value");
- const auto Bytes = bytesFromWords(Constant.IntegerValue->words(), Layout.Size);
+ const auto Bytes = bytesFromWords(Constant.IntegerValue->words(), AllocationSize);
return Streamer.emitBytes(Bytes);
}
case GenericConstantKind::Floating: {
if (!Constant.FloatingValue)
return makeUnexpected(ErrorCode::InternalError, "floating constant has no value");
- const auto Bytes = bytesFromWords(Constant.FloatingValue->words(), Layout.Size);
+ const auto Bytes = bytesFromWords(Constant.FloatingValue->words(), AllocationSize);
return Streamer.emitBytes(Bytes);
}
case GenericConstantKind::ByteString: {
- if (Constant.ByteValue.size() != Layout.Size) {
+ if (Constant.ByteValue.size() != AllocationSize) {
return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
"byte-string constant size does not match its RV64GC layout");
}
@@ -546,61 +415,57 @@ struct TypeLayout final {
case GenericConstantKind::ZeroInitializer:
case GenericConstantKind::Undef:
case GenericConstantKind::Poison:
- return Streamer.emitZeroFill(Layout.Size);
+ return Streamer.emitZeroFill(AllocationSize);
case GenericConstantKind::Aggregate: {
- const GenericConstantType &Type = resolvedType(Constant.Type);
+ const GenericConstantType &Type = Constant.Type.resolved();
std::uint64_t Offset = 0;
for (std::size_t Index = 0; Index < Constant.Elements.size(); ++Index) {
- auto ElementLayout = layoutType(Constant.Elements[Index].Type, Depth + 1);
- if (!ElementLayout)
- return std::unexpected(ElementLayout.error());
- const std::uint64_t Alignment = Type.Kind == GenericConstantTypeKind::Struct && Type.Packed
- ? 1
- : ElementLayout->Alignment;
- auto ElementOffset = alignTo(Offset, Alignment);
- if (!ElementOffset)
- return std::unexpected(ElementOffset.error());
- auto Padding = emitPadding(*ElementOffset - Offset, Streamer);
+ auto ElementSize = Layout.getTypeAllocSize(Constant.Elements[Index].Type);
+ auto ElementAlignment = Layout.getABITypeAlign(Constant.Elements[Index].Type);
+ if (!ElementSize)
+ return std::unexpected(ElementSize.error());
+ if (!ElementAlignment)
+ return std::unexpected(ElementAlignment.error());
+ const std::uint64_t Alignment =
+ Type.Kind == GenericConstantTypeKind::Struct && Type.Packed ? 1 : *ElementAlignment;
+ const std::uint64_t AlignmentMask = Alignment - 1U;
+ if (Offset > std::numeric_limits<std::uint64_t>::max() - AlignmentMask) {
+ return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
+ "aggregate constant exceeds its RV64GC layout");
+ }
+ const std::uint64_t ElementOffset = (Offset + AlignmentMask) & ~AlignmentMask;
+ if (ElementOffset > AllocationSize || *ElementSize > AllocationSize - ElementOffset) {
+ return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
+ "aggregate constant exceeds its RV64GC layout");
+ }
+ auto Padding = emitPadding(ElementOffset - Offset, Streamer);
if (!Padding)
return std::unexpected(Padding.error());
- auto Element = emitGenericConstantImpl(Constant.Elements[Index], *ElementLayout, Context,
- Streamer, Depth + 1);
+ auto Element = emitGenericConstantImpl(Constant.Elements[Index], Layout, *ElementSize,
+ Context, Streamer, Depth + 1);
if (!Element)
return std::unexpected(Element.error());
- auto End = checkedAdd(*ElementOffset, ElementLayout->Size);
- if (!End)
- return std::unexpected(End.error());
- Offset = *End;
- if (Type.Kind == GenericConstantTypeKind::Array ||
- Type.Kind == GenericConstantTypeKind::Vector) {
- auto StrideEnd = alignTo(Offset, ElementLayout->Alignment);
- if (!StrideEnd)
- return std::unexpected(StrideEnd.error());
- auto ElementPadding = emitPadding(*StrideEnd - Offset, Streamer);
- if (!ElementPadding)
- return std::unexpected(ElementPadding.error());
- Offset = *StrideEnd;
- }
+ Offset = ElementOffset + *ElementSize;
}
- if (Offset > Layout.Size) {
+ if (Offset > AllocationSize) {
return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
"aggregate constant exceeds its RV64GC layout");
}
- return emitPadding(Layout.Size - Offset, Streamer);
+ return emitPadding(AllocationSize - Offset, Streamer);
}
case GenericConstantKind::GlobalAddress:
case GenericConstantKind::BlockAddress:
case GenericConstantKind::DSOLocalEquivalent:
case GenericConstantKind::NoCFI:
case GenericConstantKind::Expression: {
- if (Layout.Size != 1 && Layout.Size != 2 && Layout.Size != 4 && Layout.Size != 8) {
+ if (AllocationSize != 1 && AllocationSize != 2 && AllocationSize != 4 && AllocationSize != 8) {
return makeUnexpected(ErrorCode::Unsupported,
"symbolic RV64GC constant has an unsupported storage size");
}
auto Expression = lowerConstantExpression(Constant, Context);
if (!Expression)
return std::unexpected(Expression.error());
- return Streamer.emitValue(std::move(*Expression), static_cast<std::uint8_t>(Layout.Size));
+ return Streamer.emitValue(std::move(*Expression), static_cast<std::uint8_t>(AllocationSize));
}
case GenericConstantKind::PointerAuth:
return makeUnexpected(ErrorCode::Unsupported,
@@ -1151,14 +1016,17 @@ Expected<void> RISCVMCTargetLowering::emitGenericConstant(const GenericConstantD
auto Verification = Constant.verify();
if (!Verification)
return std::unexpected(Verification.error());
- auto Layout = layoutType(Constant.Type);
+ auto Layout = DataLayout::parse(TargetDataLayout);
if (!Layout)
return std::unexpected(Layout.error());
- if (Layout->Size != Size) {
+ auto AllocationSize = Layout->getTypeAllocSize(Constant.Type);
+ if (!AllocationSize)
+ return std::unexpected(AllocationSize.error());
+ if (*AllocationSize != Size) {
return makeUnexpected(ErrorCode::AssemblyLoweringFailed,
"generic constant size does not match the RV64GC data layout");
}
- return emitGenericConstantImpl(Constant, *Layout, Context, Streamer);
+ return emitGenericConstantImpl(Constant, *Layout, *AllocationSize, Context, Streamer);
}
Expected<void> RISCVMCTargetLowering::emitGlobalInitializer(const GlobalInitializer &Initializer,