Skip to content

[SandboxIR] Add utility function to find the base Value for Mem instructions #112030

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions llvm/include/llvm/SandboxIR/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class Context {
}
/// Get or create a sandboxir::Constant from an existing LLVM IR \p LLVMC.
Constant *getOrCreateConstant(llvm::Constant *LLVMC);
friend class Utils; // For getMemoryBase

// Friends for getOrCreateConstant().
#define DEF_CONST(ID, CLASS) friend class CLASS;
Expand Down
10 changes: 10 additions & 0 deletions llvm/include/llvm/SandboxIR/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ class Utils {
return const_cast<Instruction *>(I);
}

/// \Returns the base Value for load or store instruction \p LSI.
template <typename LoadOrStoreT>
static Value *getMemInstructionBase(const LoadOrStoreT *LSI) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use LLVM's name getUnderlyingObject() ? getMemInstructionBase() is a better name, but since we are just wrapping LLVM's getUnderlyingObject() we should probably stick to the same name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this does more than just wrap getUnderlyingObject. It also finds the pointer operand.

static_assert(std::is_same_v<LoadOrStoreT, LoadInst> ||
std::is_same_v<LoadOrStoreT, StoreInst>,
"Expected sandboxir::Load or sandboxir::Store!");
return LSI->Ctx.getOrCreateValue(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need getOrCreateValue() ? I assume that sandbox IR would have been generated for the whole function. That would remove the need for friend class Utils in Context.

auto *V = LSI->Ctx.getValue( getUnderlyingObject(LSI->getPointerOperand()->Val));
assert(V != nullptr && "Missing Sandbox IR value!");
return V;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getUnderlyingObject returns an llvm::Value, getOrCreateValue converts that to a sandboxir::Value.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but there is also a public sandboxir::Context::getValue(llvm::Value *) that converts LLVM IR to Sandbox IR

getUnderlyingObject(LSI->getPointerOperand()->Val));
}

/// \Returns the number of bits required to represent the operands or return
/// value of \p V in \p DL.
static unsigned getNumBits(Value *V, const DataLayout &DL) {
Expand Down
32 changes: 32 additions & 0 deletions llvm/unittests/SandboxIR/UtilsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,35 @@ define void @foo(float %arg0, double %arg1, i8 %arg2, i64 %arg3, ptr %arg4) {
EXPECT_EQ(sandboxir::Utils::getNumBits(L2), 8u);
EXPECT_EQ(sandboxir::Utils::getNumBits(L3), 64u);
}

TEST_F(UtilsTest, GetMemBase) {
parseIR(C, R"IR(
define void @foo(ptr %ptrA, float %val, ptr %ptrB) {
bb:
%gepA0 = getelementptr float, ptr %ptrA, i32 0
%gepA1 = getelementptr float, ptr %ptrA, i32 1
%gepB0 = getelementptr float, ptr %ptrB, i32 0
%gepB1 = getelementptr float, ptr %ptrB, i32 1
store float %val, ptr %gepA0
store float %val, ptr %gepA1
store float %val, ptr %gepB0
store float %val, ptr %gepB1
ret void
}
)IR");
llvm::Function &Foo = *M->getFunction("foo");
sandboxir::Context Ctx(C);
sandboxir::Function *F = Ctx.createFunction(&Foo);

auto It = std::next(F->begin()->begin(), 4);
auto *St0 = cast<sandboxir::StoreInst>(&*It++);
auto *St1 = cast<sandboxir::StoreInst>(&*It++);
auto *St2 = cast<sandboxir::StoreInst>(&*It++);
auto *St3 = cast<sandboxir::StoreInst>(&*It++);
EXPECT_EQ(sandboxir::Utils::getMemInstructionBase(St0),
sandboxir::Utils::getMemInstructionBase(St1));
EXPECT_EQ(sandboxir::Utils::getMemInstructionBase(St2),
sandboxir::Utils::getMemInstructionBase(St3));
EXPECT_NE(sandboxir::Utils::getMemInstructionBase(St0),
sandboxir::Utils::getMemInstructionBase(St3));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These checks are OK, but we are not actually checking what the returned value actually is.

Some checks like this would also help:

EXPECT_EQ(sandboxir::Utils::getMemInsructionBase(St0), Ctx.getValue(LLVMSt0));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will add

}
Loading