diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h index 9e5db20b24877..1f488adbf5021 100644 --- a/llvm/include/llvm/SandboxIR/SandboxIR.h +++ b/llvm/include/llvm/SandboxIR/SandboxIR.h @@ -124,6 +124,7 @@ class GetElementPtrInst; class CastInst; class PtrToIntInst; class BitCastInst; +class AllocaInst; /// Iterator for the `Use` edges of a User's operands. /// \Returns the operand `Use` when dereferenced. @@ -240,6 +241,7 @@ class Value { friend class InvokeInst; // For getting `Val`. friend class CallBrInst; // For getting `Val`. friend class GetElementPtrInst; // For getting `Val`. + friend class AllocaInst; // For getting `Val`. friend class CastInst; // For getting `Val`. friend class PHINode; // For getting `Val`. @@ -633,6 +635,7 @@ class Instruction : public sandboxir::User { friend class InvokeInst; // For getTopmostLLVMInstruction(). friend class CallBrInst; // For getTopmostLLVMInstruction(). friend class GetElementPtrInst; // For getTopmostLLVMInstruction(). + friend class AllocaInst; // For getTopmostLLVMInstruction(). friend class CastInst; // For getTopmostLLVMInstruction(). friend class PHINode; // For getTopmostLLVMInstruction(). @@ -1393,6 +1396,103 @@ class GetElementPtrInst final : public Instruction { #endif }; +class AllocaInst final : public UnaryInstruction { + Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final { + return getOperandUseDefault(OpIdx, Verify); + } + SmallVector getLLVMInstrs() const final { + return {cast(Val)}; + } + + AllocaInst(llvm::AllocaInst *AI, Context &Ctx) + : UnaryInstruction(ClassID::Alloca, Instruction::Opcode::Alloca, AI, + Ctx) {} + friend class Context; // For constructor. + +public: + static AllocaInst *create(Type *Ty, unsigned AddrSpace, BBIterator WhereIt, + BasicBlock *WhereBB, Context &Ctx, + Value *ArraySize = nullptr, const Twine &Name = ""); + static AllocaInst *create(Type *Ty, unsigned AddrSpace, + Instruction *InsertBefore, Context &Ctx, + Value *ArraySize = nullptr, const Twine &Name = ""); + static AllocaInst *create(Type *Ty, unsigned AddrSpace, + BasicBlock *InsertAtEnd, Context &Ctx, + Value *ArraySize = nullptr, const Twine &Name = ""); + + unsigned getUseOperandNo(const Use &Use) const final { + return getUseOperandNoDefault(Use); + } + unsigned getNumOfIRInstrs() const final { return 1u; } + + /// Return true if there is an allocation size parameter to the allocation + /// instruction that is not 1. + bool isArrayAllocation() const { + return cast(Val)->isArrayAllocation(); + } + /// Get the number of elements allocated. For a simple allocation of a single + /// element, this will return a constant 1 value. + Value *getArraySize(); + const Value *getArraySize() const { + return const_cast(this)->getArraySize(); + } + /// Overload to return most specific pointer type. + PointerType *getType() const { + return cast(Val)->getType(); + } + /// Return the address space for the allocation. + unsigned getAddressSpace() const { + return cast(Val)->getAddressSpace(); + } + /// Get allocation size in bytes. Returns std::nullopt if size can't be + /// determined, e.g. in case of a VLA. + std::optional getAllocationSize(const DataLayout &DL) const { + return cast(Val)->getAllocationSize(DL); + } + /// Get allocation size in bits. Returns std::nullopt if size can't be + /// determined, e.g. in case of a VLA. + std::optional getAllocationSizeInBits(const DataLayout &DL) const { + return cast(Val)->getAllocationSizeInBits(DL); + } + /// Return the type that is being allocated by the instruction. + Type *getAllocatedType() const { + return cast(Val)->getAllocatedType(); + } + /// for use only in special circumstances that need to generically + /// transform a whole instruction (eg: IR linking and vectorization). + void setAllocatedType(Type *Ty); + /// Return the alignment of the memory that is being allocated by the + /// instruction. + Align getAlign() const { return cast(Val)->getAlign(); } + void setAlignment(Align Align); + /// Return true if this alloca is in the entry block of the function and is a + /// constant size. If so, the code generator will fold it into the + /// prolog/epilog code, so it is basically free. + bool isStaticAlloca() const { + return cast(Val)->isStaticAlloca(); + } + /// Return true if this alloca is used as an inalloca argument to a call. Such + /// allocas are never considered static even if they are in the entry block. + bool isUsedWithInAlloca() const { + return cast(Val)->isUsedWithInAlloca(); + } + /// Specify whether this alloca is used to represent the arguments to a call. + void setUsedWithInAlloca(bool V); + + static bool classof(const Value *From) { + if (auto *I = dyn_cast(From)) + return I->getSubclassID() == Instruction::ClassID::Alloca; + return false; + } +#ifndef NDEBUG + void verify() const final { + assert(isa(Val) && "Expected AllocaInst!"); + } + void dump(raw_ostream &OS) const override; + LLVM_DUMP_METHOD void dump() const override; +#endif +}; + class CastInst : public UnaryInstruction { static Opcode getCastOpcode(llvm::Instruction::CastOps CastOp) { switch (CastOp) { @@ -1727,6 +1827,8 @@ class Context { friend CallBrInst; // For createCallBrInst() GetElementPtrInst *createGetElementPtrInst(llvm::GetElementPtrInst *I); friend GetElementPtrInst; // For createGetElementPtrInst() + AllocaInst *createAllocaInst(llvm::AllocaInst *I); + friend AllocaInst; // For createAllocaInst() CastInst *createCastInst(llvm::CastInst *I); friend CastInst; // For createCastInst() PHINode *createPHINode(llvm::PHINode *I); diff --git a/llvm/include/llvm/SandboxIR/SandboxIRValues.def b/llvm/include/llvm/SandboxIR/SandboxIRValues.def index 4cb601128a507..3b16bdee6d15c 100644 --- a/llvm/include/llvm/SandboxIR/SandboxIRValues.def +++ b/llvm/include/llvm/SandboxIR/SandboxIRValues.def @@ -43,6 +43,7 @@ DEF_INSTR(Call, OP(Call), CallInst) DEF_INSTR(Invoke, OP(Invoke), InvokeInst) DEF_INSTR(CallBr, OP(CallBr), CallBrInst) DEF_INSTR(GetElementPtr, OP(GetElementPtr), GetElementPtrInst) +DEF_INSTR(Alloca, OP(Alloca), AllocaInst) DEF_INSTR(Cast, OPCODES(\ OP(ZExt) \ OP(SExt) \ diff --git a/llvm/include/llvm/SandboxIR/Tracker.h b/llvm/include/llvm/SandboxIR/Tracker.h index 3c491bf0b3f58..af6d015a81518 100644 --- a/llvm/include/llvm/SandboxIR/Tracker.h +++ b/llvm/include/llvm/SandboxIR/Tracker.h @@ -58,6 +58,7 @@ class LoadInst; class StoreInst; class Instruction; class Tracker; +class AllocaInst; /// The base class for IR Change classes. class IRChangeBase { @@ -255,6 +256,57 @@ class CallBrInstSetDefaultDest : public IRChangeBase { #endif }; +class AllocaSetAllocatedType final : public IRChangeBase { + AllocaInst *Alloca; + Type *OrigType; + +public: + AllocaSetAllocatedType(AllocaInst *Alloca, Tracker &Tracker); + void revert() final; + void accept() final {} +#ifndef NDEBUG + void dump(raw_ostream &OS) const final { + dumpCommon(OS); + OS << "AllocaSetAllocatedType"; + } + LLVM_DUMP_METHOD void dump() const final; +#endif +}; + +class AllocaSetAlignment final : public IRChangeBase { + AllocaInst *Alloca; + Align OrigAlign; + +public: + AllocaSetAlignment(AllocaInst *Alloca, Tracker &Tracker); + void revert() final; + void accept() final {} +#ifndef NDEBUG + void dump(raw_ostream &OS) const final { + dumpCommon(OS); + OS << "AllocaSetAlignment"; + } + LLVM_DUMP_METHOD void dump() const final; +#endif +}; + +class AllocaSetUsedWithInAlloca final : public IRChangeBase { + AllocaInst *Alloca; + bool Orig; + +public: + AllocaSetUsedWithInAlloca(AllocaInst *Alloca, Tracker &Tracker); + void revert() final; + void accept() final {} +#ifndef NDEBUG + void dump(raw_ostream &OS) const final { + dumpCommon(OS); + OS << "AllocaSetUsedWithInAlloca"; + } + LLVM_DUMP_METHOD void dump() const final; +#endif +}; + class CallBrInstSetIndirectDest : public IRChangeBase { CallBrInst *CallBr; unsigned Idx; diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp index 235c4574ead13..ad76698efa709 100644 --- a/llvm/lib/SandboxIR/SandboxIR.cpp +++ b/llvm/lib/SandboxIR/SandboxIR.cpp @@ -1212,6 +1212,69 @@ static llvm::Instruction::CastOps getLLVMCastOp(Instruction::Opcode Opc) { } } +AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace, BBIterator WhereIt, + BasicBlock *WhereBB, Context &Ctx, + Value *ArraySize, const Twine &Name) { + auto &Builder = Ctx.getLLVMIRBuilder(); + if (WhereIt == WhereBB->end()) + Builder.SetInsertPoint(cast(WhereBB->Val)); + else + Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction()); + auto *NewAlloca = Builder.CreateAlloca(Ty, AddrSpace, ArraySize->Val, Name); + return Ctx.createAllocaInst(NewAlloca); +} + +AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace, + Instruction *InsertBefore, Context &Ctx, + Value *ArraySize, const Twine &Name) { + return create(Ty, AddrSpace, InsertBefore->getIterator(), + InsertBefore->getParent(), Ctx, ArraySize, Name); +} + +AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace, + BasicBlock *InsertAtEnd, Context &Ctx, + Value *ArraySize, const Twine &Name) { + return create(Ty, AddrSpace, InsertAtEnd->end(), InsertAtEnd, Ctx, ArraySize, + Name); +} + +void AllocaInst::setAllocatedType(Type *Ty) { + auto &Tracker = Ctx.getTracker(); + if (Tracker.isTracking()) + Tracker.track(std::make_unique(this, Tracker)); + cast(Val)->setAllocatedType(Ty); +} + +void AllocaInst::setAlignment(Align Align) { + auto &Tracker = Ctx.getTracker(); + if (Tracker.isTracking()) + Tracker.track(std::make_unique(this, Tracker)); + cast(Val)->setAlignment(Align); +} + +void AllocaInst::setUsedWithInAlloca(bool V) { + auto &Tracker = Ctx.getTracker(); + if (Tracker.isTracking()) + Tracker.track(std::make_unique(this, Tracker)); + cast(Val)->setUsedWithInAlloca(V); +} + +Value *AllocaInst::getArraySize() { + return Ctx.getValue(cast(Val)->getArraySize()); +} + +#ifndef NDEBUG +void AllocaInst::dump(raw_ostream &OS) const { + dumpCommonPrefix(OS); + dumpCommonSuffix(OS); +} + +void AllocaInst::dump() const { + dump(dbgs()); + dbgs() << "\n"; +} +#endif // NDEBUG + Value *CastInst::create(Type *DestTy, Opcode Op, Value *Operand, BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx, const Twine &Name) { @@ -1452,6 +1515,11 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) { new GetElementPtrInst(LLVMGEP, *this)); return It->second.get(); } + case llvm::Instruction::Alloca: { + auto *LLVMAlloca = cast(LLVMV); + It->second = std::unique_ptr(new AllocaInst(LLVMAlloca, *this)); + return It->second.get(); + } case llvm::Instruction::ZExt: case llvm::Instruction::SExt: case llvm::Instruction::FPToUI: @@ -1538,7 +1606,10 @@ Context::createGetElementPtrInst(llvm::GetElementPtrInst *I) { std::unique_ptr(new GetElementPtrInst(I, *this)); return cast(registerValue(std::move(NewPtr))); } - +AllocaInst *Context::createAllocaInst(llvm::AllocaInst *I) { + auto NewPtr = std::unique_ptr(new AllocaInst(I, *this)); + return cast(registerValue(std::move(NewPtr))); +} CastInst *Context::createCastInst(llvm::CastInst *I) { auto NewPtr = std::unique_ptr(new CastInst(I, *this)); return cast(registerValue(std::move(NewPtr))); diff --git a/llvm/lib/SandboxIR/Tracker.cpp b/llvm/lib/SandboxIR/Tracker.cpp index aa18c21cd03d6..90c48a3683d83 100644 --- a/llvm/lib/SandboxIR/Tracker.cpp +++ b/llvm/lib/SandboxIR/Tracker.cpp @@ -204,6 +204,46 @@ void RemoveFromParent::dump() const { } #endif +AllocaSetAllocatedType::AllocaSetAllocatedType(AllocaInst *Alloca, + Tracker &Tracker) + : IRChangeBase(Tracker), Alloca(Alloca), + OrigType(Alloca->getAllocatedType()) {} + +void AllocaSetAllocatedType::revert() { Alloca->setAllocatedType(OrigType); } + +#ifndef NDEBUG +void AllocaSetAllocatedType::dump() const { + dump(dbgs()); + dbgs() << "\n"; +} +#endif // NDEBUG + +AllocaSetAlignment::AllocaSetAlignment(AllocaInst *Alloca, Tracker &Tracker) + : IRChangeBase(Tracker), Alloca(Alloca), OrigAlign(Alloca->getAlign()) {} + +void AllocaSetAlignment::revert() { Alloca->setAlignment(OrigAlign); } + +#ifndef NDEBUG +void AllocaSetAlignment::dump() const { + dump(dbgs()); + dbgs() << "\n"; +} +#endif // NDEBUG + +AllocaSetUsedWithInAlloca::AllocaSetUsedWithInAlloca(AllocaInst *Alloca, + Tracker &Tracker) + : IRChangeBase(Tracker), Alloca(Alloca), + Orig(Alloca->isUsedWithInAlloca()) {} + +void AllocaSetUsedWithInAlloca::revert() { Alloca->setUsedWithInAlloca(Orig); } + +#ifndef NDEBUG +void AllocaSetUsedWithInAlloca::dump() const { + dump(dbgs()); + dbgs() << "\n"; +} +#endif // NDEBUG + CallBrInstSetDefaultDest::CallBrInstSetDefaultDest(CallBrInst *CallBr, Tracker &Tracker) : IRChangeBase(Tracker), CallBr(CallBr) { diff --git a/llvm/unittests/SandboxIR/SandboxIRTest.cpp b/llvm/unittests/SandboxIR/SandboxIRTest.cpp index 550c0576e0237..4b3325d9436ef 100644 --- a/llvm/unittests/SandboxIR/SandboxIRTest.cpp +++ b/llvm/unittests/SandboxIR/SandboxIRTest.cpp @@ -1475,6 +1475,147 @@ define void @foo(ptr %ptr, <2 x ptr> %ptrs) { EXPECT_EQ(NewGEP2->getNextNode(), nullptr); } +TEST_F(SandboxIRTest, AllocaInst) { + parseIR(C, R"IR( +define void @foo() { + %allocaScalar = alloca i32, align 1024 + %allocaArray = alloca i32, i32 42 + ret void +} +)IR"); + DataLayout DL(M.get()); + llvm::Function &LLVMF = *M->getFunction("foo"); + llvm::BasicBlock *LLVMBB = &*LLVMF.begin(); + auto LLVMIt = LLVMBB->begin(); + auto *LLVMAllocaScalar = cast(&*LLVMIt++); + auto *LLVMAllocaArray = cast(&*LLVMIt++); + + sandboxir::Context Ctx(C); + sandboxir::Function *F = Ctx.createFunction(&LLVMF); + auto *BB = &*F->begin(); + auto It = BB->begin(); + auto *AllocaScalar = cast(&*It++); + auto *AllocaArray = cast(&*It++); + auto *Ret = cast(&*It++); + + // Check isArrayAllocation(). + EXPECT_EQ(AllocaScalar->isArrayAllocation(), + LLVMAllocaScalar->isArrayAllocation()); + EXPECT_EQ(AllocaArray->isArrayAllocation(), + LLVMAllocaArray->isArrayAllocation()); + // Check getArraySize(). + EXPECT_EQ(AllocaScalar->getArraySize(), + Ctx.getValue(LLVMAllocaScalar->getArraySize())); + EXPECT_EQ(AllocaArray->getArraySize(), + Ctx.getValue(LLVMAllocaArray->getArraySize())); + // Check getType(). + EXPECT_EQ(AllocaScalar->getType(), LLVMAllocaScalar->getType()); + EXPECT_EQ(AllocaArray->getType(), LLVMAllocaArray->getType()); + // Check getAddressSpace(). + EXPECT_EQ(AllocaScalar->getAddressSpace(), + LLVMAllocaScalar->getAddressSpace()); + EXPECT_EQ(AllocaArray->getAddressSpace(), LLVMAllocaArray->getAddressSpace()); + // Check getAllocationSize(). + EXPECT_EQ(AllocaScalar->getAllocationSize(DL), + LLVMAllocaScalar->getAllocationSize(DL)); + EXPECT_EQ(AllocaArray->getAllocationSize(DL), + LLVMAllocaArray->getAllocationSize(DL)); + // Check getAllocationSizeInBits(). + EXPECT_EQ(AllocaScalar->getAllocationSizeInBits(DL), + LLVMAllocaScalar->getAllocationSizeInBits(DL)); + EXPECT_EQ(AllocaArray->getAllocationSizeInBits(DL), + LLVMAllocaArray->getAllocationSizeInBits(DL)); + // Check getAllocatedType(). + EXPECT_EQ(AllocaScalar->getAllocatedType(), + LLVMAllocaScalar->getAllocatedType()); + EXPECT_EQ(AllocaArray->getAllocatedType(), + LLVMAllocaArray->getAllocatedType()); + // Check setAllocatedType(). + auto *OrigType = AllocaScalar->getAllocatedType(); + auto *NewType = PointerType::get(C, 0); + EXPECT_NE(NewType, OrigType); + AllocaScalar->setAllocatedType(NewType); + EXPECT_EQ(AllocaScalar->getAllocatedType(), NewType); + AllocaScalar->setAllocatedType(OrigType); + EXPECT_EQ(AllocaScalar->getAllocatedType(), OrigType); + // Check getAlign(). + EXPECT_EQ(AllocaScalar->getAlign(), LLVMAllocaScalar->getAlign()); + EXPECT_EQ(AllocaArray->getAlign(), LLVMAllocaArray->getAlign()); + // Check setAlignment(). + Align OrigAlign = AllocaScalar->getAlign(); + Align NewAlign(16); + EXPECT_NE(NewAlign, OrigAlign); + AllocaScalar->setAlignment(NewAlign); + EXPECT_EQ(AllocaScalar->getAlign(), NewAlign); + AllocaScalar->setAlignment(OrigAlign); + EXPECT_EQ(AllocaScalar->getAlign(), OrigAlign); + // Check isStaticAlloca(). + EXPECT_EQ(AllocaScalar->isStaticAlloca(), LLVMAllocaScalar->isStaticAlloca()); + EXPECT_EQ(AllocaArray->isStaticAlloca(), LLVMAllocaArray->isStaticAlloca()); + // Check isUsedWithInAlloca(), setUsedWithInAlloca(). + EXPECT_EQ(AllocaScalar->isUsedWithInAlloca(), + LLVMAllocaScalar->isUsedWithInAlloca()); + bool OrigUsedWithInAlloca = AllocaScalar->isUsedWithInAlloca(); + bool NewUsedWithInAlloca = true; + EXPECT_NE(NewUsedWithInAlloca, OrigUsedWithInAlloca); + AllocaScalar->setUsedWithInAlloca(NewUsedWithInAlloca); + EXPECT_EQ(AllocaScalar->isUsedWithInAlloca(), NewUsedWithInAlloca); + AllocaScalar->setUsedWithInAlloca(OrigUsedWithInAlloca); + EXPECT_EQ(AllocaScalar->isUsedWithInAlloca(), OrigUsedWithInAlloca); + + auto *Ty = Type::getInt32Ty(C); + unsigned AddrSpace = 42; + auto *PtrTy = PointerType::get(C, AddrSpace); + auto *ArraySize = sandboxir::Constant::createInt(Ty, 43, Ctx); + { + // Check create() WhereIt, WhereBB. + auto *NewI = cast(sandboxir::AllocaInst::create( + Ty, AddrSpace, /*WhereIt=*/Ret->getIterator(), + /*WhereBB=*/Ret->getParent(), Ctx, ArraySize, "NewAlloca1")); + // Check getOpcode(). + EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Alloca); + // Check getType(). + EXPECT_EQ(NewI->getType(), PtrTy); + // Check getArraySize(). + EXPECT_EQ(NewI->getArraySize(), ArraySize); + // Check getAddrSpace(). + EXPECT_EQ(NewI->getAddressSpace(), AddrSpace); + // Check instr position. + EXPECT_EQ(NewI->getNextNode(), Ret); + } + { + // Check create() InsertBefore. + auto *NewI = cast(sandboxir::AllocaInst::create( + Ty, AddrSpace, /*InsertBefore=*/Ret, Ctx, ArraySize, "NewAlloca2")); + // Check getOpcode(). + EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Alloca); + // Check getType(). + EXPECT_EQ(NewI->getType(), PtrTy); + // Check getArraySize(). + EXPECT_EQ(NewI->getArraySize(), ArraySize); + // Check getAddrSpace(). + EXPECT_EQ(NewI->getAddressSpace(), AddrSpace); + // Check instr position. + EXPECT_EQ(NewI->getNextNode(), Ret); + } + { + // Check create() InsertAtEnd. + auto *NewI = cast(sandboxir::AllocaInst::create( + Ty, AddrSpace, /*InsertAtEnd=*/BB, Ctx, ArraySize, "NewAlloca3")); + // Check getOpcode(). + EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Alloca); + // Check getType(). + EXPECT_EQ(NewI->getType(), PtrTy); + // Check getArraySize(). + EXPECT_EQ(NewI->getArraySize(), ArraySize); + // Check getAddrSpace(). + EXPECT_EQ(NewI->getAddressSpace(), AddrSpace); + // Check instr position. + EXPECT_EQ(NewI->getParent(), BB); + EXPECT_EQ(NewI->getNextNode(), nullptr); + } +} + TEST_F(SandboxIRTest, CastInst) { parseIR(C, R"IR( define void @foo(i32 %arg, float %farg, double %darg, ptr %ptr) { diff --git a/llvm/unittests/SandboxIR/TrackerTest.cpp b/llvm/unittests/SandboxIR/TrackerTest.cpp index e61258392a388..36b7c8be3446b 100644 --- a/llvm/unittests/SandboxIR/TrackerTest.cpp +++ b/llvm/unittests/SandboxIR/TrackerTest.cpp @@ -644,6 +644,51 @@ define void @foo(i8 %arg) { EXPECT_EQ(Invoke->getSuccessor(1), ExceptionBB); } +TEST_F(TrackerTest, AllocaInstSetters) { + parseIR(C, R"IR( +define void @foo(i8 %arg) { + %alloca = alloca i32, align 64 + ret void +} +)IR"); + Function &LLVMF = *M->getFunction("foo"); + sandboxir::Context Ctx(C); + auto &F = *Ctx.createFunction(&LLVMF); + auto *BB = &*F.begin(); + auto It = BB->begin(); + auto *Alloca = cast(&*It++); + + // Check setAllocatedType(). + Ctx.save(); + auto *OrigTy = Alloca->getAllocatedType(); + auto *NewTy = Type::getInt64Ty(C); + EXPECT_NE(NewTy, OrigTy); + Alloca->setAllocatedType(NewTy); + EXPECT_EQ(Alloca->getAllocatedType(), NewTy); + Ctx.revert(); + EXPECT_EQ(Alloca->getAllocatedType(), OrigTy); + + // Check setAlignment(). + Ctx.save(); + auto OrigAlign = Alloca->getAlign(); + Align NewAlign(128); + EXPECT_NE(NewAlign, OrigAlign); + Alloca->setAlignment(NewAlign); + EXPECT_EQ(Alloca->getAlign(), NewAlign); + Ctx.revert(); + EXPECT_EQ(Alloca->getAlign(), OrigAlign); + + // Check setUsedWithInAlloca(). + Ctx.save(); + auto OrigWIA = Alloca->isUsedWithInAlloca(); + bool NewWIA = true; + EXPECT_NE(NewWIA, OrigWIA); + Alloca->setUsedWithInAlloca(NewWIA); + EXPECT_EQ(Alloca->isUsedWithInAlloca(), NewWIA); + Ctx.revert(); + EXPECT_EQ(Alloca->isUsedWithInAlloca(), OrigWIA); +} + TEST_F(TrackerTest, CallBrSetters) { parseIR(C, R"IR( define void @foo(i8 %arg) {