diff --git a/llvm/include/llvm/IR/ExtMetadata.h b/llvm/include/llvm/IR/ExtMetadata.h --- a/llvm/include/llvm/IR/ExtMetadata.h +++ b/llvm/include/llvm/IR/ExtMetadata.h @@ -186,6 +186,43 @@ SmallVector> serialize() const; }; +/// !llvm.range metadata +/// +/// Represents a half-open range [lo, hi). Wrapping is allowed. +class RangeMetadata : public ExtMetadata { + APInt Lo; + APInt Hi; + +public: + RangeMetadata(LLVMContext &Ctx, const APInt &Lo, const APInt &Hi); + + static RangeMetadata *get(LLVMContext &Ctx, const APInt &Lo, const APInt &Hi); + + static bool classof(const ExtMetadata *M) { + return M->getClassId() == getClass().getId(); + } + static bool classof(const Metadata *MD) { + if (const auto *ExtMD = dyn_cast(MD)) + return classof(ExtMD); + return false; + } + + const APInt &getLo() const { return Lo; } + const APInt &getHi() const { return Hi; } + + static const ExtMetadataClass &getClass(); + +private: + class Deserializer; + + static RangeMetadata *getImpl(LLVMContext &Ctx, const APInt &Lo, + const APInt &Hi); + + static SmallVector> + serialize(const ExtMetadata *M, bool UseSchema); + static bool verifier(const ExtMetadata *M, llvm::raw_ostream &Errs); +}; + } // namespace llvm #endif // LLVM_IR_EXTMETADATA_H diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/APInt.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/ExtMetadata.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Intrinsics.h" @@ -1839,6 +1840,10 @@ #endif ConstantRange llvm::getConstantRangeFromMetadata(const MDNode &Ranges) { + if (auto *RMD = dyn_cast(&Ranges)) { + return {RMD->getLo(), RMD->getHi()}; + } + const unsigned NumRanges = Ranges.getNumOperands() / 2; assert(NumRanges >= 1 && "Must have at least one range!"); assert(Ranges.getNumOperands() % 2 == 0 && "Must be a sequence of pairs"); diff --git a/llvm/lib/IR/ExtMetadata.cpp b/llvm/lib/IR/ExtMetadata.cpp --- a/llvm/lib/IR/ExtMetadata.cpp +++ b/llvm/lib/IR/ExtMetadata.cpp @@ -162,3 +162,102 @@ F.emplace_back(K, V); return F; } + +RangeMetadata::RangeMetadata(LLVMContext &Ctx, const APInt &Lo, const APInt &Hi) + : ExtMetadata(Ctx, getClass().getId(), Metadata::Uniqued), Lo(Lo), Hi(Hi) { + assert(Lo.getBitWidth() == Hi.getBitWidth()); +} + +RangeMetadata *RangeMetadata::getImpl(LLVMContext &Ctx, const APInt &Lo, + const APInt &Hi) { + return new (0, Uniqued) RangeMetadata(Ctx, Lo, Hi); +} + +RangeMetadata *RangeMetadata::get(LLVMContext &Ctx, const APInt &Lo, + const APInt &Hi) { + RangeMetadata *MD = getImpl(Ctx, Lo, Hi); + assert(verifier(MD, llvm::dbgs())); + return MD; +} + +class RangeMetadata::Deserializer : public ExtMetadataDeserializer { + LLVMContext &Ctx; + bool IsDistinct; + APInt Lo; + APInt Hi; + +public: + Deserializer(LLVMContext &Ctx, bool IsDistinct) + : Ctx(Ctx), IsDistinct(IsDistinct) {} + + Error parseField(StringRef K, sdata::Value V) override { + if (K == "lo") { + if (!V.isAPInt()) + return sdata::makeDeserializeError("'lo' must be an integer"); + Lo = V.getAPInt(); + return Error::success(); + } + + if (K == "hi") { + if (!V.isAPInt()) + return sdata::makeDeserializeError("'hi' must be an integer"); + Hi = V.getAPInt(); + return Error::success(); + } + + return sdata::makeDeserializeError("expected 'lo' or 'hi'"); + } + + Expected finish() override { + if (IsDistinct) + return sdata::makeDeserializeError( + "!llvm.range metadata cannot be distinct"); + if (!Lo.getBitWidth()) + return sdata::makeDeserializeError("missing 'lo'"); + if (!Hi.getBitWidth()) + return sdata::makeDeserializeError("missing 'hi'"); + + auto *MD = RangeMetadata::getImpl(Ctx, Lo, Hi); + + std::string Err; + raw_string_ostream ErrStream(Err); + if (!verifier(MD, ErrStream)) + return sdata::makeDeserializeError(Err); + + return MD; + } +}; + +const ExtMetadataClass &RangeMetadata::getClass() { + static const auto Class{[]() { + ExtMetadataClass C( + "llvm.range", + [](LLVMContext &Ctx, bool IsDistinct) { + return std::unique_ptr( + new Deserializer(Ctx, IsDistinct)); + }, + &RangeMetadata::serialize); + C.setVerifier(&RangeMetadata::verifier); + return C; + }()}; + return Class; +} + +SmallVector> +RangeMetadata::serialize(const ExtMetadata *M, bool UseSchema) { + auto *R = cast(M); + SmallVector> Fields; + Fields.emplace_back("lo", R->getLo()); + Fields.emplace_back("hi", R->getHi()); + return Fields; +} + +bool RangeMetadata::verifier(const ExtMetadata *M, llvm::raw_ostream &Errs) { + auto *R = cast(M); + if (R->getLo().getBitWidth() != R->getHi().getBitWidth()) { + Errs << "range metadata bitwidth mismatch: " << R->getLo().getBitWidth() + << " (lo) vs. " << R->getHi().getBitWidth() << " (hi)\n"; + return false; + } + return true; +} diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -130,6 +130,8 @@ return true; }); registerTargetExtTypeClass(&Aarch64SVCount); + + registerExtMetadataClass(&RangeMetadata::getClass()); } LLVMContext::~LLVMContext() { delete pImpl; } diff --git a/llvm/lib/IR/MDBuilder.cpp b/llvm/lib/IR/MDBuilder.cpp --- a/llvm/lib/IR/MDBuilder.cpp +++ b/llvm/lib/IR/MDBuilder.cpp @@ -13,6 +13,7 @@ #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/ExtMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/Metadata.h" using namespace llvm; @@ -83,9 +84,7 @@ MDNode *MDBuilder::createRange(const APInt &Lo, const APInt &Hi) { assert(Lo.getBitWidth() == Hi.getBitWidth() && "Mismatched bitwidths!"); - - Type *Ty = IntegerType::get(Context, Lo.getBitWidth()); - return createRange(ConstantInt::get(Ty, Lo), ConstantInt::get(Ty, Hi)); + return RangeMetadata::get(Context, Lo, Hi); } MDNode *MDBuilder::createRange(Constant *Lo, Constant *Hi) { @@ -94,7 +93,8 @@ return nullptr; // Return the range [Lo, Hi). - return MDNode::get(Context, {createConstant(Lo), createConstant(Hi)}); + return createRange(cast(Lo)->getValue(), + cast(Hi)->getValue()); } MDNode *MDBuilder::createCallees(ArrayRef Callees) {