[llvm] [SandboxIR] Implement the InsertElementInst class (PR #102404)

Jorge Gorbe Moya via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 9 12:33:42 PDT 2024


https://github.com/slackito updated https://github.com/llvm/llvm-project/pull/102404

>From 9e5a4046d5938a963e5b05b3984e68eb35dbab96 Mon Sep 17 00:00:00 2001
From: Jorge Gorbe Moya <jgorbe at google.com>
Date: Wed, 7 Aug 2024 16:44:00 -0700
Subject: [PATCH 1/6] [SandboxIR] Implement the InsertElementInst class

Heavily based on work by @vporpo.
---
 llvm/include/llvm/SandboxIR/SandboxIR.h       | 46 +++++++++++++++
 .../llvm/SandboxIR/SandboxIRValues.def        |  1 +
 llvm/lib/SandboxIR/SandboxIR.cpp              | 57 ++++++++++++++++++-
 llvm/unittests/SandboxIR/SandboxIRTest.cpp    | 38 +++++++++++++
 4 files changed, 139 insertions(+), 3 deletions(-)

diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h
index 12ecd304ce8336..4ced87fc8f853c 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIR.h
+++ b/llvm/include/llvm/SandboxIR/SandboxIR.h
@@ -235,6 +235,7 @@ class Value {
   friend class User;              // For getting `Val`.
   friend class Use;               // For getting `Val`.
   friend class SelectInst;        // For getting `Val`.
+  friend class InsertElementInst; // For getting `Val`.
   friend class BranchInst;        // For getting `Val`.
   friend class LoadInst;          // For getting `Val`.
   friend class StoreInst;         // For getting `Val`.
@@ -631,6 +632,7 @@ class Instruction : public sandboxir::User {
   /// returns its topmost LLVM IR instruction.
   llvm::Instruction *getTopmostLLVMInstruction() const;
   friend class SelectInst;        // For getTopmostLLVMInstruction().
+  friend class InsertElementInst; // For getTopmostLLVMInstruction().
   friend class BranchInst;        // For getTopmostLLVMInstruction().
   friend class LoadInst;          // For getTopmostLLVMInstruction().
   friend class StoreInst;         // For getTopmostLLVMInstruction().
@@ -753,6 +755,48 @@ class SelectInst : public Instruction {
 #endif
 };
 
+class InsertElementInst final : public Instruction {
+  /// Use Context::createInsertElementInst(). Don't call
+  /// the constructor directly.
+  InsertElementInst(llvm::Instruction *I, Context &Ctx)
+      : Instruction(ClassID::InsertElement, Opcode::InsertElement, I, Ctx) {}
+  InsertElementInst(ClassID SubclassID, llvm::Instruction *I, Context &Ctx)
+      : Instruction(SubclassID, Opcode::InsertElement, I, Ctx) {}
+  friend class Context; // For accessing the constructor in
+                        // create*()
+  Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
+    return getOperandUseDefault(OpIdx, Verify);
+  }
+  SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final {
+    return {cast<llvm::Instruction>(Val)};
+  }
+
+public:
+  static Value *create(Value *Vec, Value *NewElt, Value *Idx,
+                       Instruction *InsertBefore, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Value *Vec, Value *NewElt, Value *Idx,
+                       BasicBlock *InsertAtEnd, Context &Ctx,
+                       const Twine &Name = "");
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::InsertElement;
+  }
+  unsigned getUseOperandNo(const Use &Use) const final {
+    return getUseOperandNoDefault(Use);
+  }
+  unsigned getNumOfIRInstrs() const final { return 1u; }
+#ifndef NDEBUG
+  void verify() const final {}
+  friend raw_ostream &operator<<(raw_ostream &OS,
+                                 const InsertElementInst &SBGI) {
+    SBGI.dump(OS);
+    return OS;
+  }
+  void dump(raw_ostream &OS) const override;
+  LLVM_DUMP_METHOD void dump() const override;
+#endif
+};
+
 class BranchInst : public Instruction {
   /// Use Context::createBranchInst(). Don't call the constructor directly.
   BranchInst(llvm::BranchInst *BI, Context &Ctx)
@@ -1845,6 +1889,8 @@ class Context {
 
   SelectInst *createSelectInst(llvm::SelectInst *SI);
   friend SelectInst; // For createSelectInst()
+  InsertElementInst *createInsertElementInst(llvm::InsertElementInst *IEI);
+  friend InsertElementInst; // For createInsertElementInst()
   BranchInst *createBranchInst(llvm::BranchInst *I);
   friend BranchInst; // For createBranchInst()
   LoadInst *createLoadInst(llvm::LoadInst *LI);
diff --git a/llvm/include/llvm/SandboxIR/SandboxIRValues.def b/llvm/include/llvm/SandboxIR/SandboxIRValues.def
index dda629fcfc747e..269aea784dcec1 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIRValues.def
+++ b/llvm/include/llvm/SandboxIR/SandboxIRValues.def
@@ -34,6 +34,7 @@ DEF_USER(Constant, Constant)
 // clang-format off
 //       ClassID,        Opcode(s),         Class
 DEF_INSTR(Opaque,        OP(Opaque),        OpaqueInst)
+DEF_INSTR(InsertElement, OP(InsertElement), InsertElementInst)
 DEF_INSTR(Select,        OP(Select),        SelectInst)
 DEF_INSTR(Br,            OP(Br),            BranchInst)
 DEF_INSTR(Load,          OP(Load),          LoadInst)
diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp
index 65e9d86ee0bdfd..70daa4df80a6d3 100644
--- a/llvm/lib/SandboxIR/SandboxIR.cpp
+++ b/llvm/lib/SandboxIR/SandboxIR.cpp
@@ -1397,6 +1397,44 @@ void OpaqueInst::dump() const {
 }
 #endif // NDEBUG
 
+Value *InsertElementInst::create(Value *Vec, Value *NewElt, Value *Idx,
+                                 Instruction *InsertBefore, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(InsertBefore->getTopmostLLVMInstruction());
+  llvm::Value *NewV =
+      Builder.CreateInsertElement(Vec->Val, NewElt->Val, Idx->Val, Name);
+  if (auto *NewInsert = dyn_cast<llvm::InsertElementInst>(NewV))
+    return Ctx.createInsertElementInst(NewInsert);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *InsertElementInst::create(Value *Vec, Value *NewElt, Value *Idx,
+                                 BasicBlock *InsertAtEnd, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  llvm::Value *NewV =
+      Builder.CreateInsertElement(Vec->Val, NewElt->Val, Idx->Val, Name);
+  if (auto *NewInsert = dyn_cast<llvm::InsertElementInst>(NewV))
+    return Ctx.createInsertElementInst(NewInsert);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+#ifndef NDEBUG
+void InsertElementInst::dump(raw_ostream &OS) const {
+  dumpCommonPrefix(OS);
+  dumpCommonSuffix(OS);
+}
+
+void InsertElementInst::dump() const {
+  dump(dbgs());
+  dbgs() << "\n";
+}
+#endif // NDEBUG
+
 Constant *Constant::createInt(Type *Ty, uint64_t V, Context &Ctx,
                               bool IsSigned) {
   llvm::Constant *LLVMC = llvm::ConstantInt::get(Ty, V, IsSigned);
@@ -1529,6 +1567,12 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
     It->second = std::unique_ptr<SelectInst>(new SelectInst(LLVMSel, *this));
     return It->second.get();
   }
+  case llvm::Instruction::InsertElement: {
+    auto *LLVMIns = cast<llvm::InsertElementInst>(LLVMV);
+    It->second = std::unique_ptr<InsertElementInst>(
+        new InsertElementInst(LLVMIns, *this));
+    return It->second.get();
+  }
   case llvm::Instruction::Br: {
     auto *LLVMBr = cast<llvm::BranchInst>(LLVMV);
     It->second = std::unique_ptr<BranchInst>(new BranchInst(LLVMBr, *this));
@@ -1607,9 +1651,9 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
     break;
   }
 
-  It->second = std::unique_ptr<OpaqueInst>(
-      new OpaqueInst(cast<llvm::Instruction>(LLVMV), *this));
-  return It->second.get();
+    It->second = std::unique_ptr<OpaqueInst>(
+        new OpaqueInst(cast<llvm::Instruction>(LLVMV), *this));
+    return It->second.get();
 }
 
 BasicBlock *Context::createBasicBlock(llvm::BasicBlock *LLVMBB) {
@@ -1626,6 +1670,13 @@ SelectInst *Context::createSelectInst(llvm::SelectInst *SI) {
   return cast<SelectInst>(registerValue(std::move(NewPtr)));
 }
 
+InsertElementInst *
+Context::createInsertElementInst(llvm::InsertElementInst *IEI) {
+  auto NewPtr =
+      std::unique_ptr<InsertElementInst>(new InsertElementInst(IEI, *this));
+  return cast<InsertElementInst>(registerValue(std::move(NewPtr)));
+}
+
 BranchInst *Context::createBranchInst(llvm::BranchInst *BI) {
   auto NewPtr = std::unique_ptr<BranchInst>(new BranchInst(BI, *this));
   return cast<BranchInst>(registerValue(std::move(NewPtr)));
diff --git a/llvm/unittests/SandboxIR/SandboxIRTest.cpp b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
index f4b23784dc36bc..840460c6c32774 100644
--- a/llvm/unittests/SandboxIR/SandboxIRTest.cpp
+++ b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
@@ -630,6 +630,44 @@ define void @foo(i1 %c0, i8 %v0, i8 %v1, i1 %c1) {
   }
 }
 
+TEST_F(SandboxIRTest, InsertElementInst) {
+  parseIR(C, R"IR(
+define void @foo(i8 %v0, i8 %v1) {
+  %ins0 = insertelement <2 x i8> poison, i8 %v0, i32 0
+  %ins1 = insertelement <2 x i8> %ins0, i8 %v1, i32 1
+  ret void
+}
+)IR");
+  Function &F = *M->getFunction("foo");
+  sandboxir::Context Ctx(C);
+  auto &SBF = *Ctx.createFunction(&F);
+  unsigned ArgIdx = 0;
+  auto *Arg0 = SBF.getArg(ArgIdx++);
+  auto *Arg1 = SBF.getArg(ArgIdx++);
+  auto *SBB = &*SBF.begin();
+  auto It = SBB->begin();
+  auto *Ins0 = cast<sandboxir::InsertElementInst>(&*It++);
+  auto *Ins1 = cast<sandboxir::InsertElementInst>(&*It++);
+  auto *Ret = &*It++;
+
+  EXPECT_EQ(Ins0->getOpcode(), sandboxir::Instruction::Opcode::InsertElement);
+  EXPECT_EQ(Ins0->getOperand(1), Arg0);
+  EXPECT_EQ(Ins1->getOperand(1), Arg1);
+  EXPECT_EQ(Ins1->getOperand(0), Ins0);
+  auto *Poison = Ins0->getOperand(0);
+  auto *Idx = Ins0->getOperand(2);
+  auto *NewI1 =
+      cast<sandboxir::InsertElementInst>(sandboxir::InsertElementInst::create(
+          Poison, Arg0, Idx, Ret, Ctx, "NewIns1"));
+  EXPECT_EQ(NewI1->getOperand(0), Poison);
+  EXPECT_EQ(NewI1->getNextNode(), Ret);
+
+  auto *NewI2 =
+      cast<sandboxir::InsertElementInst>(sandboxir::InsertElementInst::create(
+          Poison, Arg0, Idx, SBB, Ctx, "NewIns2"));
+  EXPECT_EQ(NewI2->getPrevNode(), Ret);
+}
+
 TEST_F(SandboxIRTest, BranchInst) {
   parseIR(C, R"IR(
 define void @foo(i1 %cond0, i1 %cond2) {

>From 870e1e5b61ee620d103270beb733cfe96a4277fb Mon Sep 17 00:00:00 2001
From: Jorge Gorbe Moya <jgorbe at google.com>
Date: Wed, 7 Aug 2024 16:47:49 -0700
Subject: [PATCH 2/6] fix argument name

---
 llvm/include/llvm/SandboxIR/SandboxIR.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h
index 4ced87fc8f853c..a0b3f503a89ea0 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIR.h
+++ b/llvm/include/llvm/SandboxIR/SandboxIR.h
@@ -788,8 +788,8 @@ class InsertElementInst final : public Instruction {
 #ifndef NDEBUG
   void verify() const final {}
   friend raw_ostream &operator<<(raw_ostream &OS,
-                                 const InsertElementInst &SBGI) {
-    SBGI.dump(OS);
+                                 const InsertElementInst &IEI) {
+    IEI.dump(OS);
     return OS;
   }
   void dump(raw_ostream &OS) const override;

>From c77e88c3be40a13b6dd75c785bb07f6876581a27 Mon Sep 17 00:00:00 2001
From: Jorge Gorbe Moya <jgorbe at google.com>
Date: Wed, 7 Aug 2024 16:50:40 -0700
Subject: [PATCH 3/6] fix accidental indentation change

---
 llvm/lib/SandboxIR/SandboxIR.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp
index 70daa4df80a6d3..143e8b6841fab4 100644
--- a/llvm/lib/SandboxIR/SandboxIR.cpp
+++ b/llvm/lib/SandboxIR/SandboxIR.cpp
@@ -1651,9 +1651,9 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
     break;
   }
 
-    It->second = std::unique_ptr<OpaqueInst>(
-        new OpaqueInst(cast<llvm::Instruction>(LLVMV), *this));
-    return It->second.get();
+  It->second = std::unique_ptr<OpaqueInst>(
+      new OpaqueInst(cast<llvm::Instruction>(LLVMV), *this));
+  return It->second.get();
 }
 
 BasicBlock *Context::createBasicBlock(llvm::BasicBlock *LLVMBB) {

>From 1aa4ad444ddfc0379c5083284c4c3206c88fd324 Mon Sep 17 00:00:00 2001
From: Jorge Gorbe Moya <jgorbe at google.com>
Date: Thu, 8 Aug 2024 14:28:59 -0700
Subject: [PATCH 4/6] addressed some review comments

---
 llvm/include/llvm/SandboxIR/SandboxIR.h | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h
index a0b3f503a89ea0..eb098a3f322509 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIR.h
+++ b/llvm/include/llvm/SandboxIR/SandboxIR.h
@@ -756,12 +756,9 @@ class SelectInst : public Instruction {
 };
 
 class InsertElementInst final : public Instruction {
-  /// Use Context::createInsertElementInst(). Don't call
-  /// the constructor directly.
+  /// Use Context::createInsertElementInst() instead.
   InsertElementInst(llvm::Instruction *I, Context &Ctx)
       : Instruction(ClassID::InsertElement, Opcode::InsertElement, I, Ctx) {}
-  InsertElementInst(ClassID SubclassID, llvm::Instruction *I, Context &Ctx)
-      : Instruction(SubclassID, Opcode::InsertElement, I, Ctx) {}
   friend class Context; // For accessing the constructor in
                         // create*()
   Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
@@ -781,12 +778,19 @@ class InsertElementInst final : public Instruction {
   static bool classof(const Value *From) {
     return From->getSubclassID() == ClassID::InsertElement;
   }
+  static bool isValidOperands(const Value *Vec, const Value *NewElt,
+                              const Value *Idx) {
+    return llvm::InsertElementInst::isValidOperands(Vec->Val, NewElt->Val,
+                                                    Idx->Val);
+  }
   unsigned getUseOperandNo(const Use &Use) const final {
     return getUseOperandNoDefault(Use);
   }
   unsigned getNumOfIRInstrs() const final { return 1u; }
 #ifndef NDEBUG
-  void verify() const final {}
+  void verify() const final {
+    assert(isa<llvm::InsertElementInst>(Val) && "Expected InsertElementInst");
+  }
   friend raw_ostream &operator<<(raw_ostream &OS,
                                  const InsertElementInst &IEI) {
     IEI.dump(OS);

>From e1757cc315f73dab8e9261c90bd11a850b52349a Mon Sep 17 00:00:00 2001
From: Jorge Gorbe Moya <jgorbe at google.com>
Date: Fri, 9 Aug 2024 11:54:29 -0700
Subject: [PATCH 5/6] Fix test to follow convention. Test isValidOperands.

---
 llvm/unittests/SandboxIR/SandboxIRTest.cpp | 30 +++++++++++++++-------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/llvm/unittests/SandboxIR/SandboxIRTest.cpp b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
index 840460c6c32774..3e52b05ad2e94c 100644
--- a/llvm/unittests/SandboxIR/SandboxIRTest.cpp
+++ b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
@@ -9,6 +9,7 @@
 #include "llvm/SandboxIR/SandboxIR.h"
 #include "llvm/AsmParser/Parser.h"
 #include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Instruction.h"
@@ -632,20 +633,20 @@ define void @foo(i1 %c0, i8 %v0, i8 %v1, i1 %c1) {
 
 TEST_F(SandboxIRTest, InsertElementInst) {
   parseIR(C, R"IR(
-define void @foo(i8 %v0, i8 %v1) {
+define void @foo(i8 %v0, i8 %v1, <2 x i8> %vec) {
   %ins0 = insertelement <2 x i8> poison, i8 %v0, i32 0
   %ins1 = insertelement <2 x i8> %ins0, i8 %v1, i32 1
   ret void
 }
 )IR");
-  Function &F = *M->getFunction("foo");
+  Function &LLVMF = *M->getFunction("foo");
   sandboxir::Context Ctx(C);
-  auto &SBF = *Ctx.createFunction(&F);
-  unsigned ArgIdx = 0;
-  auto *Arg0 = SBF.getArg(ArgIdx++);
-  auto *Arg1 = SBF.getArg(ArgIdx++);
-  auto *SBB = &*SBF.begin();
-  auto It = SBB->begin();
+  auto &F = *Ctx.createFunction(&LLVMF);
+  auto *Arg0 = F.getArg(0);
+  auto *Arg1 = F.getArg(1);
+  auto *ArgVec = F.getArg(2);
+  auto *BB = &*F.begin();
+  auto It = BB->begin();
   auto *Ins0 = cast<sandboxir::InsertElementInst>(&*It++);
   auto *Ins1 = cast<sandboxir::InsertElementInst>(&*It++);
   auto *Ret = &*It++;
@@ -664,8 +665,19 @@ define void @foo(i8 %v0, i8 %v1) {
 
   auto *NewI2 =
       cast<sandboxir::InsertElementInst>(sandboxir::InsertElementInst::create(
-          Poison, Arg0, Idx, SBB, Ctx, "NewIns2"));
+          Poison, Arg0, Idx, BB, Ctx, "NewIns2"));
   EXPECT_EQ(NewI2->getPrevNode(), Ret);
+
+  auto *LLVMArg0 = LLVMF.getArg(0);
+  auto *LLVMArgVec = LLVMF.getArg(2);
+  auto *Zero = sandboxir::Constant::createInt(Type::getInt8Ty(C), 0, Ctx);
+  auto *LLVMZero = llvm::ConstantInt::get(Type::getInt8Ty(C), 0);
+  EXPECT_EQ(
+      sandboxir::InsertElementInst::isValidOperands(ArgVec, Arg0, Zero),
+      llvm::InsertElementInst::isValidOperands(LLVMArgVec, LLVMArg0, LLVMZero));
+  EXPECT_EQ(
+      sandboxir::InsertElementInst::isValidOperands(Arg0, ArgVec, Zero),
+      llvm::InsertElementInst::isValidOperands(LLVMArg0, LLVMArgVec, LLVMZero));
 }
 
 TEST_F(SandboxIRTest, BranchInst) {

>From fb857ed1ef8a89374a8a1a2d4f0f21f47c19cb79 Mon Sep 17 00:00:00 2001
From: Jorge Gorbe Moya <jgorbe at google.com>
Date: Fri, 9 Aug 2024 12:33:23 -0700
Subject: [PATCH 6/6] Add missing forward decl

---
 llvm/include/llvm/SandboxIR/SandboxIR.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h
index eb098a3f322509..2865e86416a454 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIR.h
+++ b/llvm/include/llvm/SandboxIR/SandboxIR.h
@@ -111,6 +111,7 @@ class Context;
 class Function;
 class Instruction;
 class SelectInst;
+class InsertElementInst;
 class BranchInst;
 class UnaryInstruction;
 class LoadInst;



More information about the llvm-commits mailing list