Skip to content

Commit 2c7e1b8

Browse files
authored
[SandboxIR] Implement ConstantFP (#106648)
This patch implements sandboxir::ConstantFP mirroring llvm::ConstantFP.
1 parent 130eddf commit 2c7e1b8

File tree

5 files changed

+303
-2
lines changed

5 files changed

+303
-2
lines changed

llvm/include/llvm/SandboxIR/SandboxIR.h

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ namespace sandboxir {
113113

114114
class BasicBlock;
115115
class ConstantInt;
116+
class ConstantFP;
116117
class Context;
117118
class Function;
118119
class Instruction;
@@ -597,6 +598,94 @@ class ConstantInt : public Constant {
597598
#endif
598599
};
599600

601+
// TODO: This should inherit from ConstantData.
602+
class ConstantFP final : public Constant {
603+
ConstantFP(llvm::ConstantFP *C, Context &Ctx)
604+
: Constant(ClassID::ConstantFP, C, Ctx) {}
605+
friend class Context; // For constructor.
606+
607+
public:
608+
/// This returns a ConstantFP, or a vector containing a splat of a ConstantFP,
609+
/// for the specified value in the specified type. This should only be used
610+
/// for simple constant values like 2.0/1.0 etc, that are known-valid both as
611+
/// host double and as the target format.
612+
static Constant *get(Type *Ty, double V);
613+
614+
/// If Ty is a vector type, return a Constant with a splat of the given
615+
/// value. Otherwise return a ConstantFP for the given value.
616+
static Constant *get(Type *Ty, const APFloat &V);
617+
618+
static Constant *get(Type *Ty, StringRef Str);
619+
620+
static ConstantFP *get(const APFloat &V, Context &Ctx);
621+
622+
static Constant *getNaN(Type *Ty, bool Negative = false,
623+
uint64_t Payload = 0);
624+
static Constant *getQNaN(Type *Ty, bool Negative = false,
625+
APInt *Payload = nullptr);
626+
static Constant *getSNaN(Type *Ty, bool Negative = false,
627+
APInt *Payload = nullptr);
628+
static Constant *getZero(Type *Ty, bool Negative = false);
629+
630+
static Constant *getNegativeZero(Type *Ty);
631+
static Constant *getInfinity(Type *Ty, bool Negative = false);
632+
633+
/// Return true if Ty is big enough to represent V.
634+
static bool isValueValidForType(Type *Ty, const APFloat &V);
635+
636+
inline const APFloat &getValueAPF() const {
637+
return cast<llvm::ConstantFP>(Val)->getValueAPF();
638+
}
639+
inline const APFloat &getValue() const {
640+
return cast<llvm::ConstantFP>(Val)->getValue();
641+
}
642+
643+
/// Return true if the value is positive or negative zero.
644+
bool isZero() const { return cast<llvm::ConstantFP>(Val)->isZero(); }
645+
646+
/// Return true if the sign bit is set.
647+
bool isNegative() const { return cast<llvm::ConstantFP>(Val)->isNegative(); }
648+
649+
/// Return true if the value is infinity
650+
bool isInfinity() const { return cast<llvm::ConstantFP>(Val)->isInfinity(); }
651+
652+
/// Return true if the value is a NaN.
653+
bool isNaN() const { return cast<llvm::ConstantFP>(Val)->isNaN(); }
654+
655+
/// We don't rely on operator== working on double values, as it returns true
656+
/// for things that are clearly not equal, like -0.0 and 0.0.
657+
/// As such, this method can be used to do an exact bit-for-bit comparison of
658+
/// two floating point values. The version with a double operand is retained
659+
/// because it's so convenient to write isExactlyValue(2.0), but please use
660+
/// it only for simple constants.
661+
bool isExactlyValue(const APFloat &V) const {
662+
return cast<llvm::ConstantFP>(Val)->isExactlyValue(V);
663+
}
664+
665+
bool isExactlyValue(double V) const {
666+
return cast<llvm::ConstantFP>(Val)->isExactlyValue(V);
667+
}
668+
669+
/// For isa/dyn_cast.
670+
static bool classof(const sandboxir::Value *From) {
671+
return From->getSubclassID() == ClassID::ConstantFP;
672+
}
673+
674+
// TODO: Better name: getOperandNo(const Use&). Should be private.
675+
unsigned getUseOperandNo(const Use &Use) const final {
676+
llvm_unreachable("ConstantFP has no operands!");
677+
}
678+
#ifndef NDEBUG
679+
void verify() const override {
680+
assert(isa<llvm::ConstantFP>(Val) && "Expected a ConstantFP!");
681+
}
682+
void dumpOS(raw_ostream &OS) const override {
683+
dumpCommonPrefix(OS);
684+
dumpCommonSuffix(OS);
685+
}
686+
#endif
687+
};
688+
600689
/// Iterator for `Instruction`s in a `BasicBlock.
601690
/// \Returns an sandboxir::Instruction & when derereferenced.
602691
class BBIterator {
@@ -3156,7 +3245,10 @@ class Context {
31563245
Constant *getOrCreateConstant(llvm::Constant *LLVMC) {
31573246
return cast<Constant>(getOrCreateValueInternal(LLVMC, 0));
31583247
}
3159-
friend class ConstantInt; // For getOrCreateConstant().
3248+
// Friends for getOrCreateConstant().
3249+
#define DEF_CONST(ID, CLASS) friend class CLASS;
3250+
#include "llvm/SandboxIR/SandboxIRValues.def"
3251+
31603252
/// Create a sandboxir::BasicBlock for an existing LLVM IR \p BB. This will
31613253
/// also create all contents of the block.
31623254
BasicBlock *createBasicBlock(llvm::BasicBlock *BB);

llvm/include/llvm/SandboxIR/SandboxIRValues.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ DEF_USER(User, User)
2626
DEF_VALUE(Block, BasicBlock)
2727
DEF_CONST(Constant, Constant)
2828
DEF_CONST(ConstantInt, ConstantInt)
29+
DEF_CONST(ConstantFP, ConstantFP)
2930

3031
#ifndef DEF_INSTR
3132
#define DEF_INSTR(ID, OPCODE, CLASS)

llvm/include/llvm/SandboxIR/Type.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class PointerType;
2727
class VectorType;
2828
class FunctionType;
2929
#define DEF_INSTR(ID, OPCODE, CLASS) class CLASS;
30+
#define DEF_CONST(ID, CLASS) class CLASS;
3031
#include "llvm/SandboxIR/SandboxIRValues.def"
3132

3233
/// Just like llvm::Type these are immutable, unique, never get freed and can
@@ -42,7 +43,7 @@ class Type {
4243
friend class ConstantInt; // For LLVMTy.
4344
// Friend all instruction classes because `create()` functions use LLVMTy.
4445
#define DEF_INSTR(ID, OPCODE, CLASS) friend class CLASS;
45-
// TODO: Friend DEF_CONST()
46+
#define DEF_CONST(ID, CLASS) friend class CLASS;
4647
#include "llvm/SandboxIR/SandboxIRValues.def"
4748
Context &Ctx;
4849

llvm/lib/SandboxIR/SandboxIR.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2248,6 +2248,54 @@ ConstantInt *ConstantInt::get(Type *Ty, uint64_t V, bool IsSigned) {
22482248
return cast<ConstantInt>(Ty->getContext().getOrCreateConstant(LLVMC));
22492249
}
22502250

2251+
Constant *ConstantFP::get(Type *Ty, double V) {
2252+
auto *LLVMC = llvm::ConstantFP::get(Ty->LLVMTy, V);
2253+
return Ty->getContext().getOrCreateConstant(LLVMC);
2254+
}
2255+
2256+
Constant *ConstantFP::get(Type *Ty, const APFloat &V) {
2257+
auto *LLVMC = llvm::ConstantFP::get(Ty->LLVMTy, V);
2258+
return Ty->getContext().getOrCreateConstant(LLVMC);
2259+
}
2260+
2261+
Constant *ConstantFP::get(Type *Ty, StringRef Str) {
2262+
auto *LLVMC = llvm::ConstantFP::get(Ty->LLVMTy, Str);
2263+
return Ty->getContext().getOrCreateConstant(LLVMC);
2264+
}
2265+
2266+
ConstantFP *ConstantFP::get(const APFloat &V, Context &Ctx) {
2267+
auto *LLVMC = llvm::ConstantFP::get(Ctx.LLVMCtx, V);
2268+
return cast<ConstantFP>(Ctx.getOrCreateConstant(LLVMC));
2269+
}
2270+
2271+
Constant *ConstantFP::getNaN(Type *Ty, bool Negative, uint64_t Payload) {
2272+
auto *LLVMC = llvm::ConstantFP::getNaN(Ty->LLVMTy, Negative, Payload);
2273+
return cast<Constant>(Ty->getContext().getOrCreateConstant(LLVMC));
2274+
}
2275+
Constant *ConstantFP::getQNaN(Type *Ty, bool Negative, APInt *Payload) {
2276+
auto *LLVMC = llvm::ConstantFP::getQNaN(Ty->LLVMTy, Negative, Payload);
2277+
return cast<Constant>(Ty->getContext().getOrCreateConstant(LLVMC));
2278+
}
2279+
Constant *ConstantFP::getSNaN(Type *Ty, bool Negative, APInt *Payload) {
2280+
auto *LLVMC = llvm::ConstantFP::getSNaN(Ty->LLVMTy, Negative, Payload);
2281+
return cast<Constant>(Ty->getContext().getOrCreateConstant(LLVMC));
2282+
}
2283+
Constant *ConstantFP::getZero(Type *Ty, bool Negative) {
2284+
auto *LLVMC = llvm::ConstantFP::getZero(Ty->LLVMTy, Negative);
2285+
return cast<Constant>(Ty->getContext().getOrCreateConstant(LLVMC));
2286+
}
2287+
Constant *ConstantFP::getNegativeZero(Type *Ty) {
2288+
auto *LLVMC = llvm::ConstantFP::getNegativeZero(Ty->LLVMTy);
2289+
return cast<Constant>(Ty->getContext().getOrCreateConstant(LLVMC));
2290+
}
2291+
Constant *ConstantFP::getInfinity(Type *Ty, bool Negative) {
2292+
auto *LLVMC = llvm::ConstantFP::getInfinity(Ty->LLVMTy, Negative);
2293+
return cast<Constant>(Ty->getContext().getOrCreateConstant(LLVMC));
2294+
}
2295+
bool ConstantFP::isValueValidForType(Type *Ty, const APFloat &V) {
2296+
return llvm::ConstantFP::isValueValidForType(Ty->LLVMTy, V);
2297+
}
2298+
22512299
FunctionType *Function::getFunctionType() const {
22522300
return cast<FunctionType>(
22532301
Ctx.getType(cast<llvm::Function>(Val)->getFunctionType()));
@@ -2339,6 +2387,10 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
23392387
It->second = std::unique_ptr<ConstantInt>(new ConstantInt(CI, *this));
23402388
return It->second.get();
23412389
}
2390+
if (auto *CF = dyn_cast<llvm::ConstantFP>(C)) {
2391+
It->second = std::unique_ptr<ConstantFP>(new ConstantFP(CF, *this));
2392+
return It->second.get();
2393+
}
23422394
if (auto *F = dyn_cast<llvm::Function>(LLVMV))
23432395
It->second = std::unique_ptr<Function>(new Function(F, *this));
23442396
else

llvm/unittests/SandboxIR/SandboxIRTest.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,161 @@ define void @foo(i32 %v0) {
130130
EXPECT_NE(FortyThree, FortyTwo);
131131
}
132132

133+
TEST_F(SandboxIRTest, ConstantFP) {
134+
parseIR(C, R"IR(
135+
define void @foo(float %v0, double %v1) {
136+
%fadd0 = fadd float %v0, 42.0
137+
%fadd1 = fadd double %v1, 43.0
138+
ret void
139+
}
140+
)IR");
141+
Function &LLVMF = *M->getFunction("foo");
142+
sandboxir::Context Ctx(C);
143+
144+
auto &F = *Ctx.createFunction(&LLVMF);
145+
auto &BB = *F.begin();
146+
auto It = BB.begin();
147+
auto *FAdd0 = cast<sandboxir::BinaryOperator>(&*It++);
148+
auto *FAdd1 = cast<sandboxir::BinaryOperator>(&*It++);
149+
auto *FortyTwo = cast<sandboxir::ConstantFP>(FAdd0->getOperand(1));
150+
[[maybe_unused]] auto *FortyThree =
151+
cast<sandboxir::ConstantFP>(FAdd1->getOperand(1));
152+
153+
auto *FloatTy = sandboxir::Type::getFloatTy(Ctx);
154+
auto *DoubleTy = sandboxir::Type::getDoubleTy(Ctx);
155+
auto *LLVMFloatTy = Type::getFloatTy(C);
156+
auto *LLVMDoubleTy = Type::getDoubleTy(C);
157+
// Check that creating an identical constant gives us the same object.
158+
auto *NewFortyTwo = sandboxir::ConstantFP::get(FloatTy, 42.0);
159+
EXPECT_EQ(NewFortyTwo, FortyTwo);
160+
// Check get(Type, double).
161+
auto *FortyFour =
162+
cast<sandboxir::ConstantFP>(sandboxir::ConstantFP::get(FloatTy, 44.0));
163+
auto *LLVMFortyFour =
164+
cast<llvm::ConstantFP>(llvm::ConstantFP::get(LLVMFloatTy, 44.0));
165+
EXPECT_NE(FortyFour, FortyTwo);
166+
EXPECT_EQ(FortyFour, Ctx.getValue(LLVMFortyFour));
167+
// Check get(Type, APFloat).
168+
auto *FortyFive = cast<sandboxir::ConstantFP>(
169+
sandboxir::ConstantFP::get(DoubleTy, APFloat(45.0)));
170+
auto *LLVMFortyFive = cast<llvm::ConstantFP>(
171+
llvm::ConstantFP::get(LLVMDoubleTy, APFloat(45.0)));
172+
EXPECT_EQ(FortyFive, Ctx.getValue(LLVMFortyFive));
173+
// Check get(Type, StringRef).
174+
auto *FortySix = sandboxir::ConstantFP::get(FloatTy, "46.0");
175+
EXPECT_EQ(FortySix, Ctx.getValue(llvm::ConstantFP::get(LLVMFloatTy, "46.0")));
176+
// Check get(APFloat).
177+
auto *FortySeven = sandboxir::ConstantFP::get(APFloat(47.0), Ctx);
178+
EXPECT_EQ(FortySeven, Ctx.getValue(llvm::ConstantFP::get(C, APFloat(47.0))));
179+
// Check getNaN().
180+
{
181+
auto *NaN = sandboxir::ConstantFP::getNaN(FloatTy);
182+
EXPECT_EQ(NaN, Ctx.getValue(llvm::ConstantFP::getNaN(LLVMFloatTy)));
183+
}
184+
{
185+
auto *NaN = sandboxir::ConstantFP::getNaN(FloatTy, /*Negative=*/true);
186+
EXPECT_EQ(NaN, Ctx.getValue(llvm::ConstantFP::getNaN(LLVMFloatTy,
187+
/*Negative=*/true)));
188+
}
189+
{
190+
auto *NaN = sandboxir::ConstantFP::getNaN(FloatTy, /*Negative=*/true,
191+
/*Payload=*/1);
192+
EXPECT_EQ(NaN, Ctx.getValue(llvm::ConstantFP::getNaN(
193+
LLVMFloatTy, /*Negative=*/true, /*Payload=*/1)));
194+
}
195+
// Check getQNaN().
196+
{
197+
auto *QNaN = sandboxir::ConstantFP::getQNaN(FloatTy);
198+
EXPECT_EQ(QNaN, Ctx.getValue(llvm::ConstantFP::getQNaN(LLVMFloatTy)));
199+
}
200+
{
201+
auto *QNaN = sandboxir::ConstantFP::getQNaN(FloatTy, /*Negative=*/true);
202+
EXPECT_EQ(QNaN, Ctx.getValue(llvm::ConstantFP::getQNaN(LLVMFloatTy,
203+
/*Negative=*/true)));
204+
}
205+
{
206+
APInt Payload(1, 1);
207+
auto *QNaN =
208+
sandboxir::ConstantFP::getQNaN(FloatTy, /*Negative=*/true, &Payload);
209+
EXPECT_EQ(QNaN, Ctx.getValue(llvm::ConstantFP::getQNaN(
210+
LLVMFloatTy, /*Negative=*/true, &Payload)));
211+
}
212+
// Check getSNaN().
213+
{
214+
auto *SNaN = sandboxir::ConstantFP::getSNaN(FloatTy);
215+
EXPECT_EQ(SNaN, Ctx.getValue(llvm::ConstantFP::getSNaN(LLVMFloatTy)));
216+
}
217+
{
218+
auto *SNaN = sandboxir::ConstantFP::getSNaN(FloatTy, /*Negative=*/true);
219+
EXPECT_EQ(SNaN, Ctx.getValue(llvm::ConstantFP::getSNaN(LLVMFloatTy,
220+
/*Negative=*/true)));
221+
}
222+
{
223+
APInt Payload(1, 1);
224+
auto *SNaN =
225+
sandboxir::ConstantFP::getSNaN(FloatTy, /*Negative=*/true, &Payload);
226+
EXPECT_EQ(SNaN, Ctx.getValue(llvm::ConstantFP::getSNaN(
227+
LLVMFloatTy, /*Negative=*/true, &Payload)));
228+
}
229+
230+
// Check getZero().
231+
{
232+
auto *Zero = sandboxir::ConstantFP::getZero(FloatTy);
233+
EXPECT_EQ(Zero, Ctx.getValue(llvm::ConstantFP::getZero(LLVMFloatTy)));
234+
}
235+
{
236+
auto *Zero = sandboxir::ConstantFP::getZero(FloatTy, /*Negative=*/true);
237+
EXPECT_EQ(Zero, Ctx.getValue(llvm::ConstantFP::getZero(LLVMFloatTy,
238+
/*Negative=*/true)));
239+
}
240+
241+
// Check getNegativeZero().
242+
auto *NegZero = cast<sandboxir::ConstantFP>(
243+
sandboxir::ConstantFP::getNegativeZero(FloatTy));
244+
EXPECT_EQ(NegZero,
245+
Ctx.getValue(llvm::ConstantFP::getNegativeZero(LLVMFloatTy)));
246+
247+
// Check getInfinity().
248+
{
249+
auto *Inf = sandboxir::ConstantFP::getInfinity(FloatTy);
250+
EXPECT_EQ(Inf, Ctx.getValue(llvm::ConstantFP::getInfinity(LLVMFloatTy)));
251+
}
252+
{
253+
auto *Inf = sandboxir::ConstantFP::getInfinity(FloatTy, /*Negative=*/true);
254+
EXPECT_EQ(Inf, Ctx.getValue(llvm::ConstantFP::getInfinity(
255+
LLVMFloatTy, /*Negative=*/true)));
256+
}
257+
258+
// Check isValueValidForType().
259+
APFloat V(1.1);
260+
EXPECT_EQ(sandboxir::ConstantFP::isValueValidForType(FloatTy, V),
261+
llvm::ConstantFP::isValueValidForType(LLVMFloatTy, V));
262+
// Check getValueAPF().
263+
EXPECT_EQ(FortyFour->getValueAPF(), LLVMFortyFour->getValueAPF());
264+
// Check getValue().
265+
EXPECT_EQ(FortyFour->getValue(), LLVMFortyFour->getValue());
266+
// Check isZero().
267+
EXPECT_EQ(FortyFour->isZero(), LLVMFortyFour->isZero());
268+
EXPECT_TRUE(sandboxir::ConstantFP::getZero(FloatTy));
269+
EXPECT_TRUE(sandboxir::ConstantFP::getZero(FloatTy, /*Negative=*/true));
270+
// Check isNegative().
271+
EXPECT_TRUE(cast<sandboxir::ConstantFP>(
272+
sandboxir::ConstantFP::getZero(FloatTy, /*Negative=*/true))
273+
->isNegative());
274+
// Check isInfinity().
275+
EXPECT_TRUE(
276+
cast<sandboxir::ConstantFP>(sandboxir::ConstantFP::getInfinity(FloatTy))
277+
->isInfinity());
278+
// Check isNaN().
279+
EXPECT_TRUE(
280+
cast<sandboxir::ConstantFP>(sandboxir::ConstantFP::getNaN(FloatTy))
281+
->isNaN());
282+
// Check isExactlyValue(APFloat).
283+
EXPECT_TRUE(NegZero->isExactlyValue(NegZero->getValueAPF()));
284+
// Check isExactlyValue(double).
285+
EXPECT_TRUE(NegZero->isExactlyValue(-0.0));
286+
}
287+
133288
TEST_F(SandboxIRTest, Use) {
134289
parseIR(C, R"IR(
135290
define i32 @foo(i32 %v0, i32 %v1) {

0 commit comments

Comments
 (0)