Skip to content

Commit d1edef5

Browse files
[SandboxIR] Functions to find vectorizor-relevant properties (#109221)
When vectorizing, the destination type and value of stores is more relevant than the type of the instruction itself. Similarly for return instructions. These functions provide a convenient way to do that without special-casing them everywhere, and avoids the need for friending any class that needs access to Value::LLVMTy to calculate it. Open to better naming.
1 parent 6267f12 commit d1edef5

File tree

3 files changed

+120
-1
lines changed

3 files changed

+120
-1
lines changed

llvm/include/llvm/SandboxIR/Type.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class Type {
5656
friend class ConstantVector; // For LLVMTy.
5757
friend class CmpInst; // For LLVMTy. TODO: Cleanup after
5858
// sandboxir::VectorType is more complete.
59+
friend class Utils; // for LLVMTy
5960

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

llvm/include/llvm/SandboxIR/Utils.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//===- Utils.h --------------------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Collector for SandboxIR related convenience functions that don't belong in
10+
// other classes.
11+
12+
#ifndef LLVM_SANDBOXIR_UTILS_H
13+
#define LLVM_SANDBOXIR_UTILS_H
14+
15+
namespace llvm::sandboxir {
16+
17+
class Utils {
18+
public:
19+
/// \Returns the expected type of \p Value V. For most Values this is
20+
/// equivalent to getType, but for stores returns the stored type, rather
21+
/// than void, and for ReturnInsts returns the returned type.
22+
static Type *getExpectedType(const Value *V) {
23+
if (auto *I = dyn_cast<Instruction>(V)) {
24+
// A Return's value operand can be null if it returns void.
25+
if (auto *RI = dyn_cast<ReturnInst>(I)) {
26+
if (RI->getReturnValue() == nullptr)
27+
return RI->getType();
28+
}
29+
return getExpectedValue(I)->getType();
30+
}
31+
return V->getType();
32+
}
33+
34+
/// \Returns the expected Value for this instruction. For most instructions,
35+
/// this is the instruction itself, but for stores returns the stored
36+
/// operand, and for ReturnInstructions returns the returned value.
37+
static Value *getExpectedValue(const Instruction *I) {
38+
if (auto *SI = dyn_cast<StoreInst>(I))
39+
return SI->getValueOperand();
40+
if (auto *RI = dyn_cast<ReturnInst>(I))
41+
return RI->getReturnValue();
42+
return const_cast<Instruction *>(I);
43+
}
44+
45+
/// \Returns the number of bits required to represent the operands or return
46+
/// value of \p V in \p DL.
47+
static unsigned getNumBits(Value *V, const DataLayout &DL) {
48+
Type *Ty = getExpectedType(V);
49+
return DL.getTypeSizeInBits(Ty->LLVMTy);
50+
}
51+
};
52+
} // namespace llvm::sandboxir
53+
54+
#endif // LLVM_SANDBOXIR_UTILS_H

llvm/unittests/SandboxIR/SandboxIRTest.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/IR/Function.h"
1515
#include "llvm/IR/Instruction.h"
1616
#include "llvm/IR/Module.h"
17+
#include "llvm/SandboxIR/Utils.h"
1718
#include "llvm/Support/SourceMgr.h"
1819
#include "gmock/gmock-matchers.h"
1920
#include "gtest/gtest.h"
@@ -1373,6 +1374,8 @@ OperandNo: 0
13731374
EXPECT_TRUE(I0->hasNUses(1u));
13741375
EXPECT_FALSE(I0->hasNUses(2u));
13751376

1377+
// Check Value.getExpectedType
1378+
13761379
// Check User.setOperand().
13771380
Ret->setOperand(0, Arg0);
13781381
EXPECT_EQ(Ret->getOperand(0), Arg0);
@@ -1436,7 +1439,6 @@ define i32 @foo(i32 %arg0, i32 %arg1) {
14361439
Replaced = Ret->replaceUsesOfWith(I0, Arg0);
14371440
EXPECT_TRUE(Replaced);
14381441
EXPECT_EQ(Ret->getOperand(0), Arg0);
1439-
14401442
// Check RAUW on constant.
14411443
auto *Glob0 = cast<sandboxir::Constant>(I1->getOperand(0));
14421444
auto *Glob1 = cast<sandboxir::Constant>(I2->getOperand(0));
@@ -1445,6 +1447,68 @@ define i32 @foo(i32 %arg0, i32 %arg1) {
14451447
EXPECT_EQ(Glob0->getOperand(0), Glob1);
14461448
}
14471449

1450+
TEST_F(SandboxIRTest, GetExpected) {
1451+
parseIR(C, R"IR(
1452+
define float @foo(float %v, ptr %ptr) {
1453+
%add = fadd float %v, %v
1454+
store float %v, ptr %ptr
1455+
ret float %v
1456+
}
1457+
define void @bar(float %v, ptr %ptr) {
1458+
ret void
1459+
}
1460+
)IR");
1461+
llvm::Function &Foo = *M->getFunction("foo");
1462+
sandboxir::Context Ctx(C);
1463+
1464+
Ctx.createFunction(&Foo);
1465+
auto *FooBB = cast<sandboxir::BasicBlock>(Ctx.getValue(&*Foo.begin()));
1466+
auto FooIt = FooBB->begin();
1467+
auto Add = cast<sandboxir::Instruction>(&*FooIt++);
1468+
auto *S0 = cast<sandboxir::Instruction>(&*FooIt++);
1469+
auto *RetF = cast<sandboxir::Instruction>(&*FooIt++);
1470+
// getExpectedValue
1471+
EXPECT_EQ(sandboxir::Utils::getExpectedValue(Add), Add);
1472+
EXPECT_EQ(sandboxir::Utils::getExpectedValue(S0),
1473+
cast<sandboxir::StoreInst>(S0)->getValueOperand());
1474+
EXPECT_EQ(sandboxir::Utils::getExpectedValue(RetF),
1475+
cast<sandboxir::ReturnInst>(RetF)->getReturnValue());
1476+
// getExpectedType
1477+
EXPECT_EQ(sandboxir::Utils::getExpectedType(Add), Add->getType());
1478+
EXPECT_EQ(sandboxir::Utils::getExpectedType(S0),
1479+
cast<sandboxir::StoreInst>(S0)->getValueOperand()->getType());
1480+
EXPECT_EQ(sandboxir::Utils::getExpectedType(RetF),
1481+
cast<sandboxir::ReturnInst>(RetF)->getReturnValue()->getType());
1482+
1483+
// getExpectedValue for void returns
1484+
llvm::Function &Bar = *M->getFunction("bar");
1485+
Ctx.createFunction(&Bar);
1486+
auto *BarBB = cast<sandboxir::BasicBlock>(Ctx.getValue(&*Bar.begin()));
1487+
auto BarIt = BarBB->begin();
1488+
auto *RetV = cast<sandboxir::Instruction>(&*BarIt++);
1489+
EXPECT_EQ(sandboxir::Utils::getExpectedValue(RetV), nullptr);
1490+
}
1491+
1492+
TEST_F(SandboxIRTest, GetNumBits) {
1493+
parseIR(C, R"IR(
1494+
define void @foo(float %arg0, double %arg1, i8 %arg2, i64 %arg3) {
1495+
bb0:
1496+
ret void
1497+
}
1498+
)IR");
1499+
llvm::Function &Foo = *M->getFunction("foo");
1500+
sandboxir::Context Ctx(C);
1501+
sandboxir::Function *F = Ctx.createFunction(&Foo);
1502+
const DataLayout &DL = M->getDataLayout();
1503+
// getNumBits for scalars
1504+
EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(0), DL),
1505+
DL.getTypeSizeInBits(Type::getFloatTy(C)));
1506+
EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(1), DL),
1507+
DL.getTypeSizeInBits(Type::getDoubleTy(C)));
1508+
EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(2), DL), 8u);
1509+
EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(3), DL), 64u);
1510+
}
1511+
14481512
TEST_F(SandboxIRTest, RAUW_RUWIf) {
14491513
parseIR(C, R"IR(
14501514
define void @foo(ptr %ptr) {

0 commit comments

Comments
 (0)