Skip to content

Commit 3756ba3

Browse files
authored
[SandboxIR] Implement ConstantDataSequential and subclasses (#133547)
This patch implements sandboxir::ConstantDataSequential mirroring LLVM IR.
1 parent d1a0572 commit 3756ba3

File tree

6 files changed

+236
-0
lines changed

6 files changed

+236
-0
lines changed

llvm/include/llvm/SandboxIR/Constant.h

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,128 @@ class ConstantAggregateZero final : public Constant {
486486
#endif
487487
};
488488

489+
/// ConstantDataSequential - A vector or array constant whose element type is a
490+
/// simple 1/2/4/8-byte integer or half/bfloat/float/double, and whose elements
491+
/// are just simple data values (i.e. ConstantInt/ConstantFP). This Constant
492+
/// node has no operands because it stores all of the elements of the constant
493+
/// as densely packed data, instead of as Value*'s.
494+
///
495+
/// This is the common base class of ConstantDataArray and ConstantDataVector.
496+
class ConstantDataSequential : public Constant {
497+
protected:
498+
ConstantDataSequential(ClassID ID, llvm::ConstantDataSequential *C,
499+
Context &Ctx)
500+
: Constant(ID, C, Ctx) {}
501+
502+
public:
503+
/// Return true if a ConstantDataSequential can be formed with a vector or
504+
/// array of the specified element type.
505+
/// ConstantDataArray only works with normal float and int types that are
506+
/// stored densely in memory, not with things like i42 or x86_f80.
507+
static bool isElementTypeCompatible(Type *Ty) {
508+
return llvm::ConstantDataSequential::isElementTypeCompatible(Ty->LLVMTy);
509+
}
510+
/// If this is a sequential container of integers (of any size), return the
511+
/// specified element in the low bits of a uint64_t.
512+
uint64_t getElementAsInteger(unsigned ElmIdx) const {
513+
return cast<llvm::ConstantDataSequential>(Val)->getElementAsInteger(ElmIdx);
514+
}
515+
/// If this is a sequential container of integers (of any size), return the
516+
/// specified element as an APInt.
517+
APInt getElementAsAPInt(unsigned ElmIdx) const {
518+
return cast<llvm::ConstantDataSequential>(Val)->getElementAsAPInt(ElmIdx);
519+
}
520+
/// If this is a sequential container of floating point type, return the
521+
/// specified element as an APFloat.
522+
APFloat getElementAsAPFloat(unsigned ElmIdx) const {
523+
return cast<llvm::ConstantDataSequential>(Val)->getElementAsAPFloat(ElmIdx);
524+
}
525+
/// If this is an sequential container of floats, return the specified element
526+
/// as a float.
527+
float getElementAsFloat(unsigned ElmIdx) const {
528+
return cast<llvm::ConstantDataSequential>(Val)->getElementAsFloat(ElmIdx);
529+
}
530+
/// If this is an sequential container of doubles, return the specified
531+
/// element as a double.
532+
double getElementAsDouble(unsigned ElmIdx) const {
533+
return cast<llvm::ConstantDataSequential>(Val)->getElementAsDouble(ElmIdx);
534+
}
535+
/// Return a Constant for a specified index's element.
536+
/// Note that this has to compute a new constant to return, so it isn't as
537+
/// efficient as getElementAsInteger/Float/Double.
538+
Constant *getElementAsConstant(unsigned ElmIdx) const {
539+
return Ctx.getOrCreateConstant(
540+
cast<llvm::ConstantDataSequential>(Val)->getElementAsConstant(ElmIdx));
541+
}
542+
/// Return the element type of the array/vector.
543+
Type *getElementType() const {
544+
return Ctx.getType(
545+
cast<llvm::ConstantDataSequential>(Val)->getElementType());
546+
}
547+
/// Return the number of elements in the array or vector.
548+
unsigned getNumElements() const {
549+
return cast<llvm::ConstantDataSequential>(Val)->getNumElements();
550+
}
551+
/// Return the size (in bytes) of each element in the array/vector.
552+
/// The size of the elements is known to be a multiple of one byte.
553+
uint64_t getElementByteSize() const {
554+
return cast<llvm::ConstantDataSequential>(Val)->getElementByteSize();
555+
}
556+
/// This method returns true if this is an array of \p CharSize integers.
557+
bool isString(unsigned CharSize = 8) const {
558+
return cast<llvm::ConstantDataSequential>(Val)->isString(CharSize);
559+
}
560+
/// This method returns true if the array "isString", ends with a null byte,
561+
/// and does not contains any other null bytes.
562+
bool isCString() const {
563+
return cast<llvm::ConstantDataSequential>(Val)->isCString();
564+
}
565+
/// If this array is isString(), then this method returns the array as a
566+
/// StringRef. Otherwise, it asserts out.
567+
StringRef getAsString() const {
568+
return cast<llvm::ConstantDataSequential>(Val)->getAsString();
569+
}
570+
/// If this array is isCString(), then this method returns the array (without
571+
/// the trailing null byte) as a StringRef. Otherwise, it asserts out.
572+
StringRef getAsCString() const {
573+
return cast<llvm::ConstantDataSequential>(Val)->getAsCString();
574+
}
575+
/// Return the raw, underlying, bytes of this data. Note that this is an
576+
/// extremely tricky thing to work with, as it exposes the host endianness of
577+
/// the data elements.
578+
StringRef getRawDataValues() const {
579+
return cast<llvm::ConstantDataSequential>(Val)->getRawDataValues();
580+
}
581+
582+
static bool classof(const Value *From) {
583+
return From->getSubclassID() == ClassID::ConstantDataArray ||
584+
From->getSubclassID() == ClassID::ConstantDataVector;
585+
}
586+
};
587+
588+
class ConstantDataArray final : public ConstantDataSequential {
589+
ConstantDataArray(llvm::ConstantDataArray *C, Context &Ctx)
590+
: ConstantDataSequential(ClassID::ConstantDataArray, C, Ctx) {}
591+
friend class Context;
592+
593+
public:
594+
// TODO: Add missing functions.
595+
};
596+
597+
/// A vector constant whose element type is a simple 1/2/4/8-byte integer or
598+
/// float/double, and whose elements are just simple data values
599+
/// (i.e. ConstantInt/ConstantFP). This Constant node has no operands because it
600+
/// stores all of the elements of the constant as densely packed data, instead
601+
/// of as Value*'s.
602+
class ConstantDataVector final : public ConstantDataSequential {
603+
ConstantDataVector(llvm::ConstantDataVector *C, Context &Ctx)
604+
: ConstantDataSequential(ClassID::ConstantDataVector, C, Ctx) {}
605+
friend class Context;
606+
607+
public:
608+
// TODO: Add missing functions.
609+
};
610+
489611
// TODO: Inherit from ConstantData.
490612
class ConstantPointerNull final : public Constant {
491613
ConstantPointerNull(llvm::ConstantPointerNull *C, Context &Ctx)

llvm/include/llvm/SandboxIR/Context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class Context {
130130
}
131131
/// Get or create a sandboxir::Constant from an existing LLVM IR \p LLVMC.
132132
Constant *getOrCreateConstant(llvm::Constant *LLVMC);
133+
friend class ConstantDataSequential; // For getOrCreateConstant().
133134
friend class Utils; // For getMemoryBase
134135

135136
void runEraseInstrCallbacks(Instruction *I);

llvm/include/llvm/SandboxIR/Type.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class StructType;
3434
class TargetExtType;
3535
class Module;
3636
class FPMathOperator;
37+
class ConstantDataSequential;
3738
#define DEF_INSTR(ID, OPCODE, CLASS) class CLASS;
3839
#define DEF_CONST(ID, CLASS) class CLASS;
3940
#include "llvm/SandboxIR/Values.def"
@@ -63,6 +64,7 @@ class Type {
6364
friend class TargetExtType; // For LLVMTy.
6465
friend class Module; // For LLVMTy.
6566
friend class FPMathOperator; // For LLVMTy.
67+
friend class ConstantDataSequential; // For LLVMTy.
6668

6769
// Friend all instruction classes because `create()` functions use LLVMTy.
6870
#define DEF_INSTR(ID, OPCODE, CLASS) friend class CLASS;

llvm/include/llvm/SandboxIR/Values.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ DEF_VALUE(Block, BasicBlock)
2828
DEF_CONST(Constant, Constant)
2929
DEF_CONST(ConstantInt, ConstantInt)
3030
DEF_CONST(ConstantFP, ConstantFP)
31+
DEF_CONST(ConstantDataArray, ConstantDataArray)
32+
DEF_CONST(ConstantDataVector, ConstantDataVector)
3133
DEF_CONST(ConstantArray, ConstantArray)
3234
DEF_CONST(ConstantStruct, ConstantStruct)
3335
DEF_CONST(ConstantVector, ConstantVector)

llvm/lib/SandboxIR/Context.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,14 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
360360
It->second = std::unique_ptr<ConstantVector>(
361361
new ConstantVector(cast<llvm::ConstantVector>(LLVMC), *this));
362362
break;
363+
case llvm::Value::ConstantDataArrayVal:
364+
It->second = std::unique_ptr<ConstantDataArray>(
365+
new ConstantDataArray(cast<llvm::ConstantDataArray>(LLVMC), *this));
366+
break;
367+
case llvm::Value::ConstantDataVectorVal:
368+
It->second = std::unique_ptr<ConstantDataVector>(
369+
new ConstantDataVector(cast<llvm::ConstantDataVector>(LLVMC), *this));
370+
break;
363371
case llvm::Value::FunctionVal:
364372
It->second = std::unique_ptr<Function>(
365373
new Function(cast<llvm::Function>(LLVMC), *this));

llvm/unittests/SandboxIR/SandboxIRTest.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,107 @@ define void @foo(ptr %ptr, {i32, i8} %v1, <2 x i8> %v2) {
607607
EXPECT_EQ(NewVectorCAZ->getElementCount(), ElementCount::getFixed(4));
608608
}
609609

610+
// Tests ConstantDataSequential, ConstantDataArray and ConstantDataVector.
611+
TEST_F(SandboxIRTest, ConstantDataSequential) {
612+
parseIR(C, R"IR(
613+
define void @foo() {
614+
%array = extractvalue [2 x i8] [i8 0, i8 1], 0
615+
%vector = extractelement <2 x i8> <i8 0, i8 1>, i32 0
616+
%farray = extractvalue [2 x float] [float 0.0, float 1.0], 0
617+
%fvector = extractelement <2 x double> <double 0.0, double 1.0>, i32 0
618+
%string = extractvalue [6 x i8] [i8 72, i8 69, i8 76, i8 76, i8 79, i8 0], 0
619+
ret void
620+
}
621+
)IR");
622+
Function &LLVMF = *M->getFunction("foo");
623+
sandboxir::Context Ctx(C);
624+
625+
auto &F = *Ctx.createFunction(&LLVMF);
626+
auto &BB = *F.begin();
627+
auto It = BB.begin();
628+
auto *I0 = &*It++;
629+
auto *I1 = &*It++;
630+
auto *I2 = &*It++;
631+
auto *I3 = &*It++;
632+
auto *I4 = &*It++;
633+
auto *Array = cast<sandboxir::ConstantDataArray>(I0->getOperand(0));
634+
EXPECT_TRUE(isa<sandboxir::ConstantDataSequential>(Array));
635+
auto *Vector = cast<sandboxir::ConstantDataVector>(I1->getOperand(0));
636+
EXPECT_TRUE(isa<sandboxir::ConstantDataVector>(Vector));
637+
auto *FArray = cast<sandboxir::ConstantDataArray>(I2->getOperand(0));
638+
EXPECT_TRUE(isa<sandboxir::ConstantDataSequential>(FArray));
639+
auto *FVector = cast<sandboxir::ConstantDataArray>(I3->getOperand(0));
640+
EXPECT_TRUE(isa<sandboxir::ConstantDataVector>(FVector));
641+
auto *String = cast<sandboxir::ConstantDataArray>(I4->getOperand(0));
642+
EXPECT_TRUE(isa<sandboxir::ConstantDataArray>(String));
643+
644+
auto *Zero8 = sandboxir::ConstantInt::get(sandboxir::Type::getInt8Ty(Ctx), 0);
645+
auto *One8 = sandboxir::ConstantInt::get(sandboxir::Type::getInt8Ty(Ctx), 1);
646+
647+
// Check isElementTypeCompatible().
648+
for (llvm::Type *LLVMTy :
649+
{llvm::Type::getIntNTy(C, 42), llvm::Type::getInt8Ty(C)})
650+
EXPECT_EQ(llvm::ConstantDataSequential::isElementTypeCompatible(LLVMTy),
651+
sandboxir::ConstantDataSequential::isElementTypeCompatible(
652+
Ctx.getType(LLVMTy)));
653+
// Check getElementAsInteger().
654+
EXPECT_EQ(Array->getElementAsInteger(0), 0u);
655+
EXPECT_EQ(Array->getElementAsInteger(1), 1u);
656+
EXPECT_EQ(Vector->getElementAsInteger(0), 0u);
657+
EXPECT_EQ(Vector->getElementAsInteger(1), 1u);
658+
// Check getElementAsAPInt().
659+
EXPECT_EQ(Array->getElementAsAPInt(0), 0u);
660+
EXPECT_EQ(Array->getElementAsAPInt(1), 1u);
661+
EXPECT_EQ(Vector->getElementAsAPInt(0), 0u);
662+
EXPECT_EQ(Vector->getElementAsAPInt(1), 1u);
663+
// Check geteElementAsFloat().
664+
EXPECT_EQ(FArray->getElementAsFloat(0), 0.0);
665+
EXPECT_EQ(FArray->getElementAsFloat(1), 1.0);
666+
// Check getElementAsDouble().
667+
EXPECT_EQ(FVector->getElementAsDouble(0), 0.0);
668+
EXPECT_EQ(FVector->getElementAsDouble(1), 1.0);
669+
// Check getElementAsConstant().
670+
EXPECT_EQ(Array->getElementAsConstant(0), Zero8);
671+
EXPECT_EQ(Array->getElementAsConstant(1), One8);
672+
EXPECT_EQ(Vector->getElementAsConstant(0), Zero8);
673+
EXPECT_EQ(Vector->getElementAsConstant(1), One8);
674+
// Check getElementType().
675+
EXPECT_EQ(Array->getElementType(), sandboxir::Type::getInt8Ty(Ctx));
676+
EXPECT_EQ(Vector->getElementType(), sandboxir::Type::getInt8Ty(Ctx));
677+
EXPECT_EQ(FArray->getElementType(), sandboxir::Type::getFloatTy(Ctx));
678+
EXPECT_EQ(FVector->getElementType(), sandboxir::Type::getDoubleTy(Ctx));
679+
// Check getNumElements(),
680+
EXPECT_EQ(Array->getNumElements(), 2u);
681+
EXPECT_EQ(Vector->getNumElements(), 2u);
682+
EXPECT_EQ(FArray->getNumElements(), 2u);
683+
EXPECT_EQ(FVector->getNumElements(), 2u);
684+
// Check getElementByteSize().
685+
EXPECT_EQ(Array->getElementByteSize(), 1u);
686+
EXPECT_EQ(Vector->getElementByteSize(), 1u);
687+
EXPECT_EQ(FArray->getElementByteSize(), 4u);
688+
EXPECT_EQ(FVector->getElementByteSize(), 8u);
689+
// Check isString().
690+
EXPECT_EQ(Array->isString(), true);
691+
EXPECT_EQ(Vector->isString(), false);
692+
EXPECT_EQ(FArray->isString(), false);
693+
EXPECT_EQ(FVector->isString(), false);
694+
EXPECT_EQ(String->isString(), true);
695+
// Check isCString().
696+
EXPECT_EQ(Array->isCString(), false);
697+
EXPECT_EQ(Vector->isCString(), false);
698+
EXPECT_EQ(FArray->isCString(), false);
699+
EXPECT_EQ(FVector->isCString(), false);
700+
EXPECT_EQ(String->isCString(), true);
701+
// Check getAsString().
702+
char Data[] = {'H', 'E', 'L', 'L', 'O', '\0'};
703+
StringRef HelloWithNull(Data, 6);
704+
EXPECT_EQ(String->getAsString(), HelloWithNull);
705+
// Check getAsCString().
706+
EXPECT_EQ(String->getAsCString(), "HELLO");
707+
// Check getRawDataValues().
708+
EXPECT_EQ(String->getRawDataValues(), HelloWithNull);
709+
}
710+
610711
TEST_F(SandboxIRTest, ConstantPointerNull) {
611712
parseIR(C, R"IR(
612713
define ptr @foo() {

0 commit comments

Comments
 (0)