2013-01-07 16:35:46 +01:00
|
|
|
//===- llvm/unittest/IR/ConstantsTest.cpp - Constants unit tests ----------===//
|
2009-03-24 22:36:09 +01:00
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2009-03-24 22:36:09 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-01-02 12:36:10 +01:00
|
|
|
#include "llvm/IR/Constants.h"
|
2017-06-06 13:06:56 +02:00
|
|
|
#include "llvm-c/Core.h"
|
|
|
|
#include "llvm/AsmParser/Parser.h"
|
2013-01-02 12:36:10 +01:00
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
|
|
#include "llvm/IR/InstrTypes.h"
|
|
|
|
#include "llvm/IR/Instruction.h"
|
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
2015-02-23 22:51:06 +01:00
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2009-03-24 22:36:09 +01:00
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
TEST(ConstantsTest, Integer_i1) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext Context;
|
|
|
|
IntegerType *Int1 = IntegerType::get(Context, 1);
|
2021-03-15 22:26:39 +01:00
|
|
|
Constant *One = ConstantInt::get(Int1, 1, true);
|
|
|
|
Constant *Zero = ConstantInt::get(Int1, 0);
|
|
|
|
Constant *NegOne = ConstantInt::get(Int1, static_cast<uint64_t>(-1), true);
|
2009-07-25 01:12:02 +02:00
|
|
|
EXPECT_EQ(NegOne, ConstantInt::getSigned(Int1, -1));
|
2020-11-28 20:26:44 +01:00
|
|
|
Constant *Poison = PoisonValue::get(Int1);
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// Input: @b = constant i1 add(i1 1 , i1 1)
|
|
|
|
// Output: @b = constant i1 false
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(Zero, ConstantExpr::getAdd(One, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @c = constant i1 add(i1 -1, i1 1)
|
|
|
|
// @c = constant i1 false
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(Zero, ConstantExpr::getAdd(NegOne, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @d = constant i1 add(i1 -1, i1 -1)
|
|
|
|
// @d = constant i1 false
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(Zero, ConstantExpr::getAdd(NegOne, NegOne));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @e = constant i1 sub(i1 -1, i1 1)
|
|
|
|
// @e = constant i1 false
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(Zero, ConstantExpr::getSub(NegOne, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @f = constant i1 sub(i1 1 , i1 -1)
|
|
|
|
// @f = constant i1 false
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(Zero, ConstantExpr::getSub(One, NegOne));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @g = constant i1 sub(i1 1 , i1 1)
|
|
|
|
// @g = constant i1 false
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(Zero, ConstantExpr::getSub(One, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
2020-11-28 20:26:44 +01:00
|
|
|
// @h = constant i1 shl(i1 1 , i1 1) ; poison
|
|
|
|
// @h = constant i1 poison
|
|
|
|
EXPECT_EQ(Poison, ConstantExpr::getShl(One, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @i = constant i1 shl(i1 1 , i1 0)
|
|
|
|
// @i = constant i1 true
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(One, ConstantExpr::getShl(One, Zero));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
2020-11-28 20:26:44 +01:00
|
|
|
// @j = constant i1 lshr(i1 1, i1 1) ; poison
|
|
|
|
// @j = constant i1 poison
|
|
|
|
EXPECT_EQ(Poison, ConstantExpr::getLShr(One, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
2020-11-28 20:26:44 +01:00
|
|
|
// @m = constant i1 ashr(i1 1, i1 1) ; poison
|
|
|
|
// @m = constant i1 poison
|
|
|
|
EXPECT_EQ(Poison, ConstantExpr::getAShr(One, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @n = constant i1 mul(i1 -1, i1 1)
|
|
|
|
// @n = constant i1 true
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(One, ConstantExpr::getMul(NegOne, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @o = constant i1 sdiv(i1 -1, i1 1) ; overflow
|
|
|
|
// @o = constant i1 true
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(One, ConstantExpr::getSDiv(NegOne, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @p = constant i1 sdiv(i1 1 , i1 -1); overflow
|
|
|
|
// @p = constant i1 true
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(One, ConstantExpr::getSDiv(One, NegOne));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @q = constant i1 udiv(i1 -1, i1 1)
|
|
|
|
// @q = constant i1 true
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(One, ConstantExpr::getUDiv(NegOne, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @r = constant i1 udiv(i1 1, i1 -1)
|
|
|
|
// @r = constant i1 true
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(One, ConstantExpr::getUDiv(One, NegOne));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @s = constant i1 srem(i1 -1, i1 1) ; overflow
|
|
|
|
// @s = constant i1 false
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(Zero, ConstantExpr::getSRem(NegOne, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @t = constant i1 urem(i1 -1, i1 1)
|
|
|
|
// @t = constant i1 false
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(Zero, ConstantExpr::getURem(NegOne, One));
|
2009-03-24 22:36:09 +01:00
|
|
|
|
|
|
|
// @u = constant i1 srem(i1 1, i1 -1) ; overflow
|
|
|
|
// @u = constant i1 false
|
2009-07-29 21:18:13 +02:00
|
|
|
EXPECT_EQ(Zero, ConstantExpr::getSRem(One, NegOne));
|
2009-03-24 22:36:09 +01:00
|
|
|
}
|
|
|
|
|
2009-04-24 07:30:14 +02:00
|
|
|
TEST(ConstantsTest, IntSigns) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext Context;
|
|
|
|
IntegerType *Int8Ty = Type::getInt8Ty(Context);
|
2009-07-25 01:12:02 +02:00
|
|
|
EXPECT_EQ(100, ConstantInt::get(Int8Ty, 100, false)->getSExtValue());
|
|
|
|
EXPECT_EQ(100, ConstantInt::get(Int8Ty, 100, true)->getSExtValue());
|
|
|
|
EXPECT_EQ(100, ConstantInt::getSigned(Int8Ty, 100)->getSExtValue());
|
|
|
|
EXPECT_EQ(-50, ConstantInt::get(Int8Ty, 206)->getSExtValue());
|
|
|
|
EXPECT_EQ(-50, ConstantInt::getSigned(Int8Ty, -50)->getSExtValue());
|
|
|
|
EXPECT_EQ(206U, ConstantInt::getSigned(Int8Ty, -50)->getZExtValue());
|
2009-04-24 07:30:14 +02:00
|
|
|
|
|
|
|
// Overflow is handled by truncation.
|
2009-07-25 01:12:02 +02:00
|
|
|
EXPECT_EQ(0x3b, ConstantInt::get(Int8Ty, 0x13b)->getSExtValue());
|
2009-04-24 07:30:14 +02:00
|
|
|
}
|
|
|
|
|
2010-12-29 02:33:36 +01:00
|
|
|
TEST(ConstantsTest, FP128Test) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext Context;
|
|
|
|
Type *FP128Ty = Type::getFP128Ty(Context);
|
2010-12-29 02:33:36 +01:00
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
IntegerType *Int128Ty = Type::getIntNTy(Context, 128);
|
2010-12-29 02:33:36 +01:00
|
|
|
Constant *Zero128 = Constant::getNullValue(Int128Ty);
|
|
|
|
Constant *X = ConstantExpr::getUIToFP(Zero128, FP128Ty);
|
|
|
|
EXPECT_TRUE(isa<ConstantFP>(X));
|
|
|
|
}
|
|
|
|
|
2013-01-16 15:41:46 +01:00
|
|
|
TEST(ConstantsTest, PointerCast) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext C;
|
2013-01-16 15:41:46 +01:00
|
|
|
Type *Int8PtrTy = Type::getInt8PtrTy(C);
|
|
|
|
Type *Int32PtrTy = Type::getInt32PtrTy(C);
|
|
|
|
Type *Int64Ty = Type::getInt64Ty(C);
|
2020-06-16 23:55:32 +02:00
|
|
|
VectorType *Int8PtrVecTy = FixedVectorType::get(Int8PtrTy, 4);
|
|
|
|
VectorType *Int32PtrVecTy = FixedVectorType::get(Int32PtrTy, 4);
|
|
|
|
VectorType *Int64VecTy = FixedVectorType::get(Int64Ty, 4);
|
2013-01-16 15:41:46 +01:00
|
|
|
|
|
|
|
// ptrtoint i8* to i64
|
2021-03-15 22:26:39 +01:00
|
|
|
EXPECT_EQ(
|
|
|
|
Constant::getNullValue(Int64Ty),
|
|
|
|
ConstantExpr::getPointerCast(Constant::getNullValue(Int8PtrTy), Int64Ty));
|
2013-01-16 15:41:46 +01:00
|
|
|
|
|
|
|
// bitcast i8* to i32*
|
|
|
|
EXPECT_EQ(Constant::getNullValue(Int32PtrTy),
|
2021-03-15 22:26:39 +01:00
|
|
|
ConstantExpr::getPointerCast(Constant::getNullValue(Int8PtrTy),
|
|
|
|
Int32PtrTy));
|
2013-01-16 15:41:46 +01:00
|
|
|
|
|
|
|
// ptrtoint <4 x i8*> to <4 x i64>
|
|
|
|
EXPECT_EQ(Constant::getNullValue(Int64VecTy),
|
2021-03-15 22:26:39 +01:00
|
|
|
ConstantExpr::getPointerCast(Constant::getNullValue(Int8PtrVecTy),
|
|
|
|
Int64VecTy));
|
2013-01-16 15:41:46 +01:00
|
|
|
|
|
|
|
// bitcast <4 x i8*> to <4 x i32*>
|
|
|
|
EXPECT_EQ(Constant::getNullValue(Int32PtrVecTy),
|
2021-03-15 22:26:39 +01:00
|
|
|
ConstantExpr::getPointerCast(Constant::getNullValue(Int8PtrVecTy),
|
|
|
|
Int32PtrVecTy));
|
2016-05-21 02:14:04 +02:00
|
|
|
|
|
|
|
Type *Int32Ptr1Ty = Type::getInt32PtrTy(C, 1);
|
|
|
|
ConstantInt *K = ConstantInt::get(Type::getInt64Ty(C), 1234);
|
|
|
|
|
|
|
|
// Make sure that addrspacecast of inttoptr is not folded away.
|
2021-03-15 22:26:39 +01:00
|
|
|
EXPECT_NE(K, ConstantExpr::getAddrSpaceCast(
|
|
|
|
ConstantExpr::getIntToPtr(K, Int32PtrTy), Int32Ptr1Ty));
|
|
|
|
EXPECT_NE(K, ConstantExpr::getAddrSpaceCast(
|
|
|
|
ConstantExpr::getIntToPtr(K, Int32Ptr1Ty), Int32PtrTy));
|
2016-05-21 02:14:04 +02:00
|
|
|
|
|
|
|
Constant *NullInt32Ptr0 = Constant::getNullValue(Int32PtrTy);
|
|
|
|
Constant *NullInt32Ptr1 = Constant::getNullValue(Int32Ptr1Ty);
|
|
|
|
|
|
|
|
// Make sure that addrspacecast of null is not folded away.
|
|
|
|
EXPECT_NE(Constant::getNullValue(Int32PtrTy),
|
|
|
|
ConstantExpr::getAddrSpaceCast(NullInt32Ptr0, Int32Ptr1Ty));
|
|
|
|
|
|
|
|
EXPECT_NE(Constant::getNullValue(Int32Ptr1Ty),
|
|
|
|
ConstantExpr::getAddrSpaceCast(NullInt32Ptr1, Int32PtrTy));
|
2013-01-16 15:41:46 +01:00
|
|
|
}
|
|
|
|
|
[IR] De-virtualize ~Value to save a vptr
Summary:
Implements PR889
Removing the virtual table pointer from Value saves 1% of RSS when doing
LTO of llc on Linux. The impact on time was positive, but too noisy to
conclusively say that performance improved. Here is a link to the
spreadsheet with the original data:
https://docs.google.com/spreadsheets/d/1F4FHir0qYnV0MEp2sYYp_BuvnJgWlWPhWOwZ6LbW7W4/edit?usp=sharing
This change makes it invalid to directly delete a Value, User, or
Instruction pointer. Instead, such code can be rewritten to a null check
and a call Value::deleteValue(). Value objects tend to have their
lifetimes managed through iplist, so for the most part, this isn't a big
deal. However, there are some places where LLVM deletes values, and
those places had to be migrated to deleteValue. I have also created
llvm::unique_value, which has a custom deleter, so it can be used in
place of std::unique_ptr<Value>.
I had to add the "DerivedUser" Deleter escape hatch for MemorySSA, which
derives from User outside of lib/IR. Code in IR cannot include MemorySSA
headers or call the MemoryAccess object destructors without introducing
a circular dependency, so we need some level of indirection.
Unfortunately, no class derived from User may have any virtual methods,
because adding a virtual method would break User::getHungOffOperands(),
which assumes that it can find the use list immediately prior to the
User object. I've added a static_assert to the appropriate OperandTraits
templates to help people avoid this trap.
Reviewers: chandlerc, mehdi_amini, pete, dberlin, george.burgess.iv
Reviewed By: chandlerc
Subscribers: krytarowski, eraman, george.burgess.iv, mzolotukhin, Prazek, nlewycky, hans, inglorion, pcc, tejohnson, dberlin, llvm-commits
Differential Revision: https://reviews.llvm.org/D31261
llvm-svn: 303362
2017-05-18 19:24:10 +02:00
|
|
|
#define CHECK(x, y) \
|
|
|
|
{ \
|
|
|
|
std::string __s; \
|
|
|
|
raw_string_ostream __o(__s); \
|
|
|
|
Instruction *__I = cast<ConstantExpr>(x)->getAsInstruction(); \
|
|
|
|
__I->print(__o); \
|
|
|
|
__I->deleteValue(); \
|
|
|
|
__o.flush(); \
|
|
|
|
EXPECT_EQ(std::string(" <badref> = " y), __s); \
|
2012-11-17 18:56:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConstantsTest, AsInstructionsTest) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext Context;
|
|
|
|
std::unique_ptr<Module> M(new Module("MyModule", Context));
|
2012-11-17 18:56:30 +01:00
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
Type *Int64Ty = Type::getInt64Ty(Context);
|
|
|
|
Type *Int32Ty = Type::getInt32Ty(Context);
|
|
|
|
Type *Int16Ty = Type::getInt16Ty(Context);
|
|
|
|
Type *Int1Ty = Type::getInt1Ty(Context);
|
|
|
|
Type *FloatTy = Type::getFloatTy(Context);
|
|
|
|
Type *DoubleTy = Type::getDoubleTy(Context);
|
2012-11-17 18:56:30 +01:00
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
Constant *Global =
|
|
|
|
M->getOrInsertGlobal("dummy", PointerType::getUnqual(Int32Ty));
|
|
|
|
Constant *Global2 =
|
|
|
|
M->getOrInsertGlobal("dummy2", PointerType::getUnqual(Int32Ty));
|
2012-11-17 18:56:30 +01:00
|
|
|
|
|
|
|
Constant *P0 = ConstantExpr::getPtrToInt(Global, Int32Ty);
|
|
|
|
Constant *P1 = ConstantExpr::getUIToFP(P0, FloatTy);
|
|
|
|
Constant *P2 = ConstantExpr::getUIToFP(P0, DoubleTy);
|
|
|
|
Constant *P3 = ConstantExpr::getTrunc(P0, Int1Ty);
|
|
|
|
Constant *P4 = ConstantExpr::getPtrToInt(Global2, Int32Ty);
|
|
|
|
Constant *P5 = ConstantExpr::getUIToFP(P4, FloatTy);
|
2020-06-16 23:55:32 +02:00
|
|
|
Constant *P6 = ConstantExpr::getBitCast(P4, FixedVectorType::get(Int16Ty, 2));
|
2012-11-17 18:56:30 +01:00
|
|
|
|
|
|
|
Constant *One = ConstantInt::get(Int32Ty, 1);
|
2015-04-24 09:42:35 +02:00
|
|
|
Constant *Two = ConstantInt::get(Int64Ty, 2);
|
2016-04-14 23:59:01 +02:00
|
|
|
Constant *Big = ConstantInt::get(Context, APInt{256, uint64_t(-1), true});
|
2015-04-27 11:30:49 +02:00
|
|
|
Constant *Elt = ConstantInt::get(Int16Ty, 2015);
|
2020-11-27 03:04:04 +01:00
|
|
|
Constant *Poison16 = PoisonValue::get(Int16Ty);
|
2021-03-15 22:26:39 +01:00
|
|
|
Constant *Undef64 = UndefValue::get(Int64Ty);
|
2020-11-27 03:04:04 +01:00
|
|
|
Constant *PoisonV16 = PoisonValue::get(P6->getType());
|
2012-11-17 18:56:30 +01:00
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
#define P0STR "ptrtoint (i32** @dummy to i32)"
|
|
|
|
#define P1STR "uitofp (i32 ptrtoint (i32** @dummy to i32) to float)"
|
|
|
|
#define P2STR "uitofp (i32 ptrtoint (i32** @dummy to i32) to double)"
|
|
|
|
#define P3STR "ptrtoint (i32** @dummy to i1)"
|
|
|
|
#define P4STR "ptrtoint (i32** @dummy2 to i32)"
|
|
|
|
#define P5STR "uitofp (i32 ptrtoint (i32** @dummy2 to i32) to float)"
|
|
|
|
#define P6STR "bitcast (i32 ptrtoint (i32** @dummy2 to i32) to <2 x i16>)"
|
2012-11-17 18:56:30 +01:00
|
|
|
|
|
|
|
CHECK(ConstantExpr::getNeg(P0), "sub i32 0, " P0STR);
|
2019-05-05 18:07:09 +02:00
|
|
|
CHECK(ConstantExpr::getFNeg(P1), "fneg float " P1STR);
|
2012-11-17 18:56:30 +01:00
|
|
|
CHECK(ConstantExpr::getNot(P0), "xor i32 " P0STR ", -1");
|
|
|
|
CHECK(ConstantExpr::getAdd(P0, P0), "add i32 " P0STR ", " P0STR);
|
2021-03-15 22:26:39 +01:00
|
|
|
CHECK(ConstantExpr::getAdd(P0, P0, false, true),
|
|
|
|
"add nsw i32 " P0STR ", " P0STR);
|
|
|
|
CHECK(ConstantExpr::getAdd(P0, P0, true, true),
|
|
|
|
"add nuw nsw i32 " P0STR ", " P0STR);
|
2012-11-17 18:56:30 +01:00
|
|
|
CHECK(ConstantExpr::getFAdd(P1, P1), "fadd float " P1STR ", " P1STR);
|
|
|
|
CHECK(ConstantExpr::getSub(P0, P0), "sub i32 " P0STR ", " P0STR);
|
|
|
|
CHECK(ConstantExpr::getFSub(P1, P1), "fsub float " P1STR ", " P1STR);
|
|
|
|
CHECK(ConstantExpr::getMul(P0, P0), "mul i32 " P0STR ", " P0STR);
|
|
|
|
CHECK(ConstantExpr::getFMul(P1, P1), "fmul float " P1STR ", " P1STR);
|
|
|
|
CHECK(ConstantExpr::getUDiv(P0, P0), "udiv i32 " P0STR ", " P0STR);
|
|
|
|
CHECK(ConstantExpr::getSDiv(P0, P0), "sdiv i32 " P0STR ", " P0STR);
|
|
|
|
CHECK(ConstantExpr::getFDiv(P1, P1), "fdiv float " P1STR ", " P1STR);
|
|
|
|
CHECK(ConstantExpr::getURem(P0, P0), "urem i32 " P0STR ", " P0STR);
|
|
|
|
CHECK(ConstantExpr::getSRem(P0, P0), "srem i32 " P0STR ", " P0STR);
|
|
|
|
CHECK(ConstantExpr::getFRem(P1, P1), "frem float " P1STR ", " P1STR);
|
|
|
|
CHECK(ConstantExpr::getAnd(P0, P0), "and i32 " P0STR ", " P0STR);
|
|
|
|
CHECK(ConstantExpr::getOr(P0, P0), "or i32 " P0STR ", " P0STR);
|
|
|
|
CHECK(ConstantExpr::getXor(P0, P0), "xor i32 " P0STR ", " P0STR);
|
|
|
|
CHECK(ConstantExpr::getShl(P0, P0), "shl i32 " P0STR ", " P0STR);
|
|
|
|
CHECK(ConstantExpr::getShl(P0, P0, true), "shl nuw i32 " P0STR ", " P0STR);
|
2021-03-15 22:26:39 +01:00
|
|
|
CHECK(ConstantExpr::getShl(P0, P0, false, true),
|
|
|
|
"shl nsw i32 " P0STR ", " P0STR);
|
2012-11-17 18:56:30 +01:00
|
|
|
CHECK(ConstantExpr::getLShr(P0, P0, false), "lshr i32 " P0STR ", " P0STR);
|
2021-03-15 22:26:39 +01:00
|
|
|
CHECK(ConstantExpr::getLShr(P0, P0, true),
|
|
|
|
"lshr exact i32 " P0STR ", " P0STR);
|
2012-11-17 18:56:30 +01:00
|
|
|
CHECK(ConstantExpr::getAShr(P0, P0, false), "ashr i32 " P0STR ", " P0STR);
|
2021-03-15 22:26:39 +01:00
|
|
|
CHECK(ConstantExpr::getAShr(P0, P0, true),
|
|
|
|
"ashr exact i32 " P0STR ", " P0STR);
|
2012-11-17 18:56:30 +01:00
|
|
|
|
|
|
|
CHECK(ConstantExpr::getSExt(P0, Int64Ty), "sext i32 " P0STR " to i64");
|
|
|
|
CHECK(ConstantExpr::getZExt(P0, Int64Ty), "zext i32 " P0STR " to i64");
|
2021-03-15 22:26:39 +01:00
|
|
|
CHECK(ConstantExpr::getFPTrunc(P2, FloatTy),
|
|
|
|
"fptrunc double " P2STR " to float");
|
|
|
|
CHECK(ConstantExpr::getFPExtend(P1, DoubleTy),
|
|
|
|
"fpext float " P1STR " to double");
|
2012-11-17 18:56:30 +01:00
|
|
|
|
|
|
|
CHECK(ConstantExpr::getExactUDiv(P0, P0), "udiv exact i32 " P0STR ", " P0STR);
|
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
CHECK(ConstantExpr::getSelect(P3, P0, P4),
|
|
|
|
"select i1 " P3STR ", i32 " P0STR ", i32 " P4STR);
|
|
|
|
CHECK(ConstantExpr::getICmp(CmpInst::ICMP_EQ, P0, P4),
|
|
|
|
"icmp eq i32 " P0STR ", " P4STR);
|
|
|
|
CHECK(ConstantExpr::getFCmp(CmpInst::FCMP_ULT, P1, P5),
|
|
|
|
"fcmp ult float " P1STR ", " P5STR);
|
2012-11-17 18:56:30 +01:00
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
std::vector<Constant *> V;
|
2012-11-17 18:56:30 +01:00
|
|
|
V.push_back(One);
|
|
|
|
// FIXME: getGetElementPtr() actually creates an inbounds ConstantGEP,
|
|
|
|
// not a normal one!
|
2021-03-15 22:26:39 +01:00
|
|
|
// CHECK(ConstantExpr::getGetElementPtr(Global, V, false),
|
[opaque pointer type] Add textual IR support for explicit type parameter to getelementptr instruction
One of several parallel first steps to remove the target type of pointers,
replacing them with a single opaque pointer type.
This adds an explicit type parameter to the gep instruction so that when the
first parameter becomes an opaque pointer type, the type to gep through is
still available to the instructions.
* This doesn't modify gep operators, only instructions (operators will be
handled separately)
* Textual IR changes only. Bitcode (including upgrade) and changing the
in-memory representation will be in separate changes.
* geps of vectors are transformed as:
getelementptr <4 x float*> %x, ...
->getelementptr float, <4 x float*> %x, ...
Then, once the opaque pointer type is introduced, this will ultimately look
like:
getelementptr float, <4 x ptr> %x
with the unambiguous interpretation that it is a vector of pointers to float.
* address spaces remain on the pointer, not the type:
getelementptr float addrspace(1)* %x
->getelementptr float, float addrspace(1)* %x
Then, eventually:
getelementptr float, ptr addrspace(1) %x
Importantly, the massive amount of test case churn has been automated by
same crappy python code. I had to manually update a few test cases that
wouldn't fit the script's model (r228970,r229196,r229197,r229198). The
python script just massages stdin and writes the result to stdout, I
then wrapped that in a shell script to handle replacing files, then
using the usual find+xargs to migrate all the files.
update.py:
import fileinput
import sys
import re
ibrep = re.compile(r"(^.*?[^%\w]getelementptr inbounds )(((?:<\d* x )?)(.*?)(| addrspace\(\d\)) *\*(|>)(?:$| *(?:%|@|null|undef|blockaddress|getelementptr|addrspacecast|bitcast|inttoptr|\[\[[a-zA-Z]|\{\{).*$))")
normrep = re.compile( r"(^.*?[^%\w]getelementptr )(((?:<\d* x )?)(.*?)(| addrspace\(\d\)) *\*(|>)(?:$| *(?:%|@|null|undef|blockaddress|getelementptr|addrspacecast|bitcast|inttoptr|\[\[[a-zA-Z]|\{\{).*$))")
def conv(match, line):
if not match:
return line
line = match.groups()[0]
if len(match.groups()[5]) == 0:
line += match.groups()[2]
line += match.groups()[3]
line += ", "
line += match.groups()[1]
line += "\n"
return line
for line in sys.stdin:
if line.find("getelementptr ") == line.find("getelementptr inbounds"):
if line.find("getelementptr inbounds") != line.find("getelementptr inbounds ("):
line = conv(re.match(ibrep, line), line)
elif line.find("getelementptr ") != line.find("getelementptr ("):
line = conv(re.match(normrep, line), line)
sys.stdout.write(line)
apply.sh:
for name in "$@"
do
python3 `dirname "$0"`/update.py < "$name" > "$name.tmp" && mv "$name.tmp" "$name"
rm -f "$name.tmp"
done
The actual commands:
From llvm/src:
find test/ -name *.ll | xargs ./apply.sh
From llvm/src/tools/clang:
find test/ -name *.mm -o -name *.m -o -name *.cpp -o -name *.c | xargs -I '{}' ../../apply.sh "{}"
From llvm/src/tools/polly:
find test/ -name *.ll | xargs ./apply.sh
After that, check-all (with llvm, clang, clang-tools-extra, lld,
compiler-rt, and polly all checked out).
The extra 'rm' in the apply.sh script is due to a few files in clang's test
suite using interesting unicode stuff that my python script was throwing
exceptions on. None of those files needed to be migrated, so it seemed
sufficient to ignore those cases.
Reviewers: rafael, dexonsmith, grosser
Differential Revision: http://reviews.llvm.org/D7636
llvm-svn: 230786
2015-02-27 20:29:02 +01:00
|
|
|
// "getelementptr i32*, i32** @dummy, i32 1");
|
2015-04-02 20:55:32 +02:00
|
|
|
CHECK(ConstantExpr::getInBoundsGetElementPtr(PointerType::getUnqual(Int32Ty),
|
|
|
|
Global, V),
|
[opaque pointer type] Add textual IR support for explicit type parameter to getelementptr instruction
One of several parallel first steps to remove the target type of pointers,
replacing them with a single opaque pointer type.
This adds an explicit type parameter to the gep instruction so that when the
first parameter becomes an opaque pointer type, the type to gep through is
still available to the instructions.
* This doesn't modify gep operators, only instructions (operators will be
handled separately)
* Textual IR changes only. Bitcode (including upgrade) and changing the
in-memory representation will be in separate changes.
* geps of vectors are transformed as:
getelementptr <4 x float*> %x, ...
->getelementptr float, <4 x float*> %x, ...
Then, once the opaque pointer type is introduced, this will ultimately look
like:
getelementptr float, <4 x ptr> %x
with the unambiguous interpretation that it is a vector of pointers to float.
* address spaces remain on the pointer, not the type:
getelementptr float addrspace(1)* %x
->getelementptr float, float addrspace(1)* %x
Then, eventually:
getelementptr float, ptr addrspace(1) %x
Importantly, the massive amount of test case churn has been automated by
same crappy python code. I had to manually update a few test cases that
wouldn't fit the script's model (r228970,r229196,r229197,r229198). The
python script just massages stdin and writes the result to stdout, I
then wrapped that in a shell script to handle replacing files, then
using the usual find+xargs to migrate all the files.
update.py:
import fileinput
import sys
import re
ibrep = re.compile(r"(^.*?[^%\w]getelementptr inbounds )(((?:<\d* x )?)(.*?)(| addrspace\(\d\)) *\*(|>)(?:$| *(?:%|@|null|undef|blockaddress|getelementptr|addrspacecast|bitcast|inttoptr|\[\[[a-zA-Z]|\{\{).*$))")
normrep = re.compile( r"(^.*?[^%\w]getelementptr )(((?:<\d* x )?)(.*?)(| addrspace\(\d\)) *\*(|>)(?:$| *(?:%|@|null|undef|blockaddress|getelementptr|addrspacecast|bitcast|inttoptr|\[\[[a-zA-Z]|\{\{).*$))")
def conv(match, line):
if not match:
return line
line = match.groups()[0]
if len(match.groups()[5]) == 0:
line += match.groups()[2]
line += match.groups()[3]
line += ", "
line += match.groups()[1]
line += "\n"
return line
for line in sys.stdin:
if line.find("getelementptr ") == line.find("getelementptr inbounds"):
if line.find("getelementptr inbounds") != line.find("getelementptr inbounds ("):
line = conv(re.match(ibrep, line), line)
elif line.find("getelementptr ") != line.find("getelementptr ("):
line = conv(re.match(normrep, line), line)
sys.stdout.write(line)
apply.sh:
for name in "$@"
do
python3 `dirname "$0"`/update.py < "$name" > "$name.tmp" && mv "$name.tmp" "$name"
rm -f "$name.tmp"
done
The actual commands:
From llvm/src:
find test/ -name *.ll | xargs ./apply.sh
From llvm/src/tools/clang:
find test/ -name *.mm -o -name *.m -o -name *.cpp -o -name *.c | xargs -I '{}' ../../apply.sh "{}"
From llvm/src/tools/polly:
find test/ -name *.ll | xargs ./apply.sh
After that, check-all (with llvm, clang, clang-tools-extra, lld,
compiler-rt, and polly all checked out).
The extra 'rm' in the apply.sh script is due to a few files in clang's test
suite using interesting unicode stuff that my python script was throwing
exceptions on. None of those files needed to be migrated, so it seemed
sufficient to ignore those cases.
Reviewers: rafael, dexonsmith, grosser
Differential Revision: http://reviews.llvm.org/D7636
llvm-svn: 230786
2015-02-27 20:29:02 +01:00
|
|
|
"getelementptr inbounds i32*, i32** @dummy, i32 1");
|
2012-11-17 18:56:30 +01:00
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
CHECK(ConstantExpr::getExtractElement(P6, One),
|
|
|
|
"extractelement <2 x i16> " P6STR ", i32 1");
|
2015-04-24 09:42:35 +02:00
|
|
|
|
2020-11-27 03:04:04 +01:00
|
|
|
EXPECT_EQ(Poison16, ConstantExpr::getExtractElement(P6, Two));
|
|
|
|
EXPECT_EQ(Poison16, ConstantExpr::getExtractElement(P6, Big));
|
|
|
|
EXPECT_EQ(Poison16, ConstantExpr::getExtractElement(P6, Undef64));
|
2015-04-27 11:30:49 +02:00
|
|
|
|
|
|
|
EXPECT_EQ(Elt, ConstantExpr::getExtractElement(
|
2020-11-28 20:26:44 +01:00
|
|
|
ConstantExpr::getInsertElement(P6, Elt, One), One));
|
|
|
|
EXPECT_EQ(PoisonV16, ConstantExpr::getInsertElement(P6, Elt, Two));
|
|
|
|
EXPECT_EQ(PoisonV16, ConstantExpr::getInsertElement(P6, Elt, Big));
|
2020-11-27 03:04:04 +01:00
|
|
|
EXPECT_EQ(PoisonV16, ConstantExpr::getInsertElement(P6, Elt, Undef64));
|
2012-11-17 18:56:30 +01:00
|
|
|
}
|
|
|
|
|
2014-05-13 03:23:21 +02:00
|
|
|
#ifdef GTEST_HAS_DEATH_TEST
|
|
|
|
#ifndef NDEBUG
|
|
|
|
TEST(ConstantsTest, ReplaceWithConstantTest) {
|
2016-04-14 23:59:01 +02:00
|
|
|
LLVMContext Context;
|
|
|
|
std::unique_ptr<Module> M(new Module("MyModule", Context));
|
2014-05-13 03:23:21 +02:00
|
|
|
|
2016-04-14 23:59:01 +02:00
|
|
|
Type *Int32Ty = Type::getInt32Ty(Context);
|
2014-05-13 03:23:21 +02:00
|
|
|
Constant *One = ConstantInt::get(Int32Ty, 1);
|
|
|
|
|
|
|
|
Constant *Global =
|
|
|
|
M->getOrInsertGlobal("dummy", PointerType::getUnqual(Int32Ty));
|
2015-04-02 20:55:32 +02:00
|
|
|
Constant *GEP = ConstantExpr::getGetElementPtr(
|
|
|
|
PointerType::getUnqual(Int32Ty), Global, One);
|
2014-05-13 03:23:21 +02:00
|
|
|
EXPECT_DEATH(Global->replaceAllUsesWith(GEP),
|
|
|
|
"this->replaceAllUsesWith\\(expr\\(this\\)\\) is NOT valid!");
|
|
|
|
}
|
2014-05-16 21:35:39 +02:00
|
|
|
|
2014-05-13 03:23:21 +02:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2012-11-17 18:56:30 +01:00
|
|
|
#undef CHECK
|
|
|
|
|
2014-08-19 18:39:58 +02:00
|
|
|
TEST(ConstantsTest, ConstantArrayReplaceWithConstant) {
|
|
|
|
LLVMContext Context;
|
|
|
|
std::unique_ptr<Module> M(new Module("MyModule", Context));
|
|
|
|
|
|
|
|
Type *IntTy = Type::getInt8Ty(Context);
|
|
|
|
ArrayType *ArrayTy = ArrayType::get(IntTy, 2);
|
|
|
|
Constant *A01Vals[2] = {ConstantInt::get(IntTy, 0),
|
|
|
|
ConstantInt::get(IntTy, 1)};
|
|
|
|
Constant *A01 = ConstantArray::get(ArrayTy, A01Vals);
|
|
|
|
|
|
|
|
Constant *Global = new GlobalVariable(*M, IntTy, false,
|
|
|
|
GlobalValue::ExternalLinkage, nullptr);
|
|
|
|
Constant *GlobalInt = ConstantExpr::getPtrToInt(Global, IntTy);
|
|
|
|
Constant *A0GVals[2] = {ConstantInt::get(IntTy, 0), GlobalInt};
|
|
|
|
Constant *A0G = ConstantArray::get(ArrayTy, A0GVals);
|
|
|
|
ASSERT_NE(A01, A0G);
|
|
|
|
|
|
|
|
GlobalVariable *RefArray =
|
|
|
|
new GlobalVariable(*M, ArrayTy, false, GlobalValue::ExternalLinkage, A0G);
|
|
|
|
ASSERT_EQ(A0G, RefArray->getInitializer());
|
|
|
|
|
|
|
|
GlobalInt->replaceAllUsesWith(ConstantInt::get(IntTy, 1));
|
|
|
|
ASSERT_EQ(A01, RefArray->getInitializer());
|
|
|
|
}
|
|
|
|
|
2014-08-19 22:03:35 +02:00
|
|
|
TEST(ConstantsTest, ConstantExprReplaceWithConstant) {
|
|
|
|
LLVMContext Context;
|
|
|
|
std::unique_ptr<Module> M(new Module("MyModule", Context));
|
|
|
|
|
|
|
|
Type *IntTy = Type::getInt8Ty(Context);
|
|
|
|
Constant *G1 = new GlobalVariable(*M, IntTy, false,
|
|
|
|
GlobalValue::ExternalLinkage, nullptr);
|
|
|
|
Constant *G2 = new GlobalVariable(*M, IntTy, false,
|
|
|
|
GlobalValue::ExternalLinkage, nullptr);
|
|
|
|
ASSERT_NE(G1, G2);
|
|
|
|
|
|
|
|
Constant *Int1 = ConstantExpr::getPtrToInt(G1, IntTy);
|
|
|
|
Constant *Int2 = ConstantExpr::getPtrToInt(G2, IntTy);
|
|
|
|
ASSERT_NE(Int1, Int2);
|
|
|
|
|
|
|
|
GlobalVariable *Ref =
|
|
|
|
new GlobalVariable(*M, IntTy, false, GlobalValue::ExternalLinkage, Int1);
|
|
|
|
ASSERT_EQ(Int1, Ref->getInitializer());
|
|
|
|
|
|
|
|
G1->replaceAllUsesWith(G2);
|
|
|
|
ASSERT_EQ(Int2, Ref->getInitializer());
|
|
|
|
}
|
|
|
|
|
2014-08-19 23:18:21 +02:00
|
|
|
TEST(ConstantsTest, GEPReplaceWithConstant) {
|
|
|
|
LLVMContext Context;
|
|
|
|
std::unique_ptr<Module> M(new Module("MyModule", Context));
|
|
|
|
|
|
|
|
Type *IntTy = Type::getInt32Ty(Context);
|
2015-09-14 20:01:59 +02:00
|
|
|
Type *PtrTy = PointerType::get(IntTy, 0);
|
2014-08-19 23:18:21 +02:00
|
|
|
auto *C1 = ConstantInt::get(IntTy, 1);
|
|
|
|
auto *Placeholder = new GlobalVariable(
|
|
|
|
*M, IntTy, false, GlobalValue::ExternalWeakLinkage, nullptr);
|
2015-04-02 20:55:32 +02:00
|
|
|
auto *GEP = ConstantExpr::getGetElementPtr(IntTy, Placeholder, C1);
|
2014-08-19 23:18:21 +02:00
|
|
|
ASSERT_EQ(GEP->getOperand(0), Placeholder);
|
|
|
|
|
|
|
|
auto *Ref =
|
|
|
|
new GlobalVariable(*M, PtrTy, false, GlobalValue::ExternalLinkage, GEP);
|
|
|
|
ASSERT_EQ(GEP, Ref->getInitializer());
|
|
|
|
|
|
|
|
auto *Global = new GlobalVariable(*M, PtrTy, false,
|
|
|
|
GlobalValue::ExternalLinkage, nullptr);
|
2015-09-14 20:01:59 +02:00
|
|
|
auto *Alias = GlobalAlias::create(IntTy, 0, GlobalValue::ExternalLinkage,
|
2014-08-19 23:18:21 +02:00
|
|
|
"alias", Global, M.get());
|
|
|
|
Placeholder->replaceAllUsesWith(Alias);
|
|
|
|
ASSERT_EQ(GEP, Ref->getInitializer());
|
|
|
|
ASSERT_EQ(GEP->getOperand(0), Alias);
|
|
|
|
}
|
|
|
|
|
2015-02-23 22:51:06 +01:00
|
|
|
TEST(ConstantsTest, AliasCAPI) {
|
|
|
|
LLVMContext Context;
|
|
|
|
SMDiagnostic Error;
|
|
|
|
std::unique_ptr<Module> M =
|
|
|
|
parseAssemblyString("@g = global i32 42", Error, Context);
|
|
|
|
GlobalVariable *G = M->getGlobalVariable("g");
|
|
|
|
Type *I16Ty = Type::getInt16Ty(Context);
|
|
|
|
Type *I16PTy = PointerType::get(I16Ty, 0);
|
|
|
|
Constant *Aliasee = ConstantExpr::getBitCast(G, I16PTy);
|
|
|
|
LLVMValueRef AliasRef =
|
|
|
|
LLVMAddAlias(wrap(M.get()), wrap(I16PTy), wrap(Aliasee), "a");
|
|
|
|
ASSERT_EQ(unwrap<GlobalAlias>(AliasRef)->getAliasee(), Aliasee);
|
|
|
|
}
|
|
|
|
|
2015-12-08 04:01:16 +01:00
|
|
|
static std::string getNameOfType(Type *T) {
|
|
|
|
std::string S;
|
|
|
|
raw_string_ostream RSOS(S);
|
|
|
|
T->print(RSOS);
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2015-12-09 22:21:07 +01:00
|
|
|
TEST(ConstantsTest, BuildConstantDataArrays) {
|
|
|
|
LLVMContext Context;
|
|
|
|
|
|
|
|
for (Type *T : {Type::getInt8Ty(Context), Type::getInt16Ty(Context),
|
|
|
|
Type::getInt32Ty(Context), Type::getInt64Ty(Context)}) {
|
|
|
|
ArrayType *ArrayTy = ArrayType::get(T, 2);
|
|
|
|
Constant *Vals[] = {ConstantInt::get(T, 0), ConstantInt::get(T, 1)};
|
2021-03-10 00:37:04 +01:00
|
|
|
Constant *CA = ConstantArray::get(ArrayTy, Vals);
|
|
|
|
ASSERT_TRUE(isa<ConstantDataArray>(CA)) << " T = " << getNameOfType(T);
|
|
|
|
auto *CDA = cast<ConstantDataArray>(CA);
|
|
|
|
Constant *CA2 = ConstantDataArray::getRaw(
|
|
|
|
CDA->getRawDataValues(), CDA->getNumElements(), CDA->getElementType());
|
|
|
|
ASSERT_TRUE(CA == CA2) << " T = " << getNameOfType(T);
|
2015-12-09 22:21:07 +01:00
|
|
|
}
|
|
|
|
|
2021-03-10 00:37:04 +01:00
|
|
|
for (Type *T : {Type::getHalfTy(Context), Type::getBFloatTy(Context),
|
|
|
|
Type::getFloatTy(Context), Type::getDoubleTy(Context)}) {
|
2015-12-09 22:21:07 +01:00
|
|
|
ArrayType *ArrayTy = ArrayType::get(T, 2);
|
|
|
|
Constant *Vals[] = {ConstantFP::get(T, 0), ConstantFP::get(T, 1)};
|
2021-03-10 00:37:04 +01:00
|
|
|
Constant *CA = ConstantArray::get(ArrayTy, Vals);
|
|
|
|
ASSERT_TRUE(isa<ConstantDataArray>(CA)) << " T = " << getNameOfType(T);
|
|
|
|
auto *CDA = cast<ConstantDataArray>(CA);
|
|
|
|
Constant *CA2 = ConstantDataArray::getRaw(
|
|
|
|
CDA->getRawDataValues(), CDA->getNumElements(), CDA->getElementType());
|
|
|
|
ASSERT_TRUE(CA == CA2) << " T = " << getNameOfType(T);
|
2015-12-09 22:21:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-08 04:01:16 +01:00
|
|
|
TEST(ConstantsTest, BuildConstantDataVectors) {
|
|
|
|
LLVMContext Context;
|
|
|
|
|
|
|
|
for (Type *T : {Type::getInt8Ty(Context), Type::getInt16Ty(Context),
|
|
|
|
Type::getInt32Ty(Context), Type::getInt64Ty(Context)}) {
|
|
|
|
Constant *Vals[] = {ConstantInt::get(T, 0), ConstantInt::get(T, 1)};
|
2021-03-10 00:37:04 +01:00
|
|
|
Constant *CV = ConstantVector::get(Vals);
|
|
|
|
ASSERT_TRUE(isa<ConstantDataVector>(CV)) << " T = " << getNameOfType(T);
|
|
|
|
auto *CDV = cast<ConstantDataVector>(CV);
|
|
|
|
Constant *CV2 = ConstantDataVector::getRaw(
|
|
|
|
CDV->getRawDataValues(), CDV->getNumElements(), CDV->getElementType());
|
|
|
|
ASSERT_TRUE(CV == CV2) << " T = " << getNameOfType(T);
|
2015-12-08 04:01:16 +01:00
|
|
|
}
|
|
|
|
|
2021-03-10 00:37:04 +01:00
|
|
|
for (Type *T : {Type::getHalfTy(Context), Type::getBFloatTy(Context),
|
|
|
|
Type::getFloatTy(Context), Type::getDoubleTy(Context)}) {
|
2015-12-08 04:01:16 +01:00
|
|
|
Constant *Vals[] = {ConstantFP::get(T, 0), ConstantFP::get(T, 1)};
|
2021-03-10 00:37:04 +01:00
|
|
|
Constant *CV = ConstantVector::get(Vals);
|
|
|
|
ASSERT_TRUE(isa<ConstantDataVector>(CV)) << " T = " << getNameOfType(T);
|
|
|
|
auto *CDV = cast<ConstantDataVector>(CV);
|
|
|
|
Constant *CV2 = ConstantDataVector::getRaw(
|
|
|
|
CDV->getRawDataValues(), CDV->getNumElements(), CDV->getElementType());
|
|
|
|
ASSERT_TRUE(CV == CV2) << " T = " << getNameOfType(T);
|
2015-12-08 04:01:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-14 20:30:32 +01:00
|
|
|
TEST(ConstantsTest, BitcastToGEP) {
|
|
|
|
LLVMContext Context;
|
|
|
|
std::unique_ptr<Module> M(new Module("MyModule", Context));
|
|
|
|
|
|
|
|
auto *i32 = Type::getInt32Ty(Context);
|
|
|
|
auto *U = StructType::create(Context, "Unsized");
|
|
|
|
Type *EltTys[] = {i32, U};
|
|
|
|
auto *S = StructType::create(EltTys);
|
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
auto *G =
|
|
|
|
new GlobalVariable(*M, S, false, GlobalValue::ExternalLinkage, nullptr);
|
2015-12-14 20:30:32 +01:00
|
|
|
auto *PtrTy = PointerType::get(i32, 0);
|
|
|
|
auto *C = ConstantExpr::getBitCast(G, PtrTy);
|
2018-05-05 03:57:00 +02:00
|
|
|
ASSERT_EQ(cast<ConstantExpr>(C)->getOpcode(), Instruction::BitCast);
|
2015-12-14 20:30:32 +01:00
|
|
|
}
|
|
|
|
|
2019-03-08 11:44:06 +01:00
|
|
|
bool foldFuncPtrAndConstToNull(LLVMContext &Context, Module *TheModule,
|
2019-10-15 13:24:36 +02:00
|
|
|
uint64_t AndValue,
|
|
|
|
MaybeAlign FunctionAlign = llvm::None) {
|
2019-03-08 11:44:06 +01:00
|
|
|
Type *VoidType(Type::getVoidTy(Context));
|
|
|
|
FunctionType *FuncType(FunctionType::get(VoidType, false));
|
2021-03-15 22:26:39 +01:00
|
|
|
Function *Func(
|
|
|
|
Function::Create(FuncType, GlobalValue::ExternalLinkage, "", TheModule));
|
2019-03-08 11:44:06 +01:00
|
|
|
|
2019-10-15 13:24:36 +02:00
|
|
|
if (FunctionAlign)
|
|
|
|
Func->setAlignment(*FunctionAlign);
|
2019-03-08 11:44:06 +01:00
|
|
|
|
|
|
|
IntegerType *ConstantIntType(Type::getInt32Ty(Context));
|
|
|
|
ConstantInt *TheConstant(ConstantInt::get(ConstantIntType, AndValue));
|
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
Constant *TheConstantExpr(ConstantExpr::getPtrToInt(Func, ConstantIntType));
|
2019-03-08 11:44:06 +01:00
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
bool Result =
|
|
|
|
ConstantExpr::get(Instruction::And, TheConstantExpr, TheConstant)
|
|
|
|
->isNullValue();
|
2019-03-08 11:44:06 +01:00
|
|
|
|
|
|
|
if (!TheModule) {
|
|
|
|
// If the Module exists then it will delete the Function.
|
|
|
|
delete Func;
|
|
|
|
}
|
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
return Result;
|
2019-03-08 11:44:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConstantsTest, FoldFunctionPtrAlignUnknownAnd2) {
|
|
|
|
LLVMContext Context;
|
|
|
|
Module TheModule("TestModule", Context);
|
|
|
|
// When the DataLayout doesn't specify a function pointer alignment we
|
|
|
|
// assume in this case that it is 4 byte aligned. This is a bug but we can't
|
|
|
|
// fix it directly because it causes a code size regression on X86.
|
|
|
|
// FIXME: This test should be changed once existing targets have
|
|
|
|
// appropriate defaults. See associated FIXME in ConstantFoldBinaryInstruction
|
|
|
|
ASSERT_TRUE(foldFuncPtrAndConstToNull(Context, &TheModule, 2));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConstantsTest, DontFoldFunctionPtrAlignUnknownAnd4) {
|
|
|
|
LLVMContext Context;
|
|
|
|
Module TheModule("TestModule", Context);
|
|
|
|
ASSERT_FALSE(foldFuncPtrAndConstToNull(Context, &TheModule, 4));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConstantsTest, FoldFunctionPtrAlign4) {
|
|
|
|
LLVMContext Context;
|
|
|
|
Module TheModule("TestModule", Context);
|
2021-03-15 22:26:39 +01:00
|
|
|
const char *AlignmentStrings[] = {"Fi32", "Fn32"};
|
2019-03-08 11:44:06 +01:00
|
|
|
|
|
|
|
for (unsigned AndValue = 1; AndValue <= 2; ++AndValue) {
|
|
|
|
for (const char *AlignmentString : AlignmentStrings) {
|
|
|
|
TheModule.setDataLayout(AlignmentString);
|
|
|
|
ASSERT_TRUE(foldFuncPtrAndConstToNull(Context, &TheModule, AndValue));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConstantsTest, DontFoldFunctionPtrAlign1) {
|
|
|
|
LLVMContext Context;
|
|
|
|
Module TheModule("TestModule", Context);
|
2021-03-15 22:26:39 +01:00
|
|
|
const char *AlignmentStrings[] = {"Fi8", "Fn8"};
|
2019-03-08 11:44:06 +01:00
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
for (const char *AlignmentString : AlignmentStrings) {
|
2019-03-08 11:44:06 +01:00
|
|
|
TheModule.setDataLayout(AlignmentString);
|
|
|
|
ASSERT_FALSE(foldFuncPtrAndConstToNull(Context, &TheModule, 2));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConstantsTest, FoldFunctionAlign4PtrAlignMultiple) {
|
|
|
|
LLVMContext Context;
|
|
|
|
Module TheModule("TestModule", Context);
|
|
|
|
TheModule.setDataLayout("Fn8");
|
2019-10-15 13:24:36 +02:00
|
|
|
ASSERT_TRUE(foldFuncPtrAndConstToNull(Context, &TheModule, 2, Align(4)));
|
2019-03-08 11:44:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConstantsTest, DontFoldFunctionAlign4PtrAlignIndependent) {
|
|
|
|
LLVMContext Context;
|
|
|
|
Module TheModule("TestModule", Context);
|
|
|
|
TheModule.setDataLayout("Fi8");
|
2019-10-15 13:24:36 +02:00
|
|
|
ASSERT_FALSE(foldFuncPtrAndConstToNull(Context, &TheModule, 2, Align(4)));
|
2019-03-08 11:44:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConstantsTest, DontFoldFunctionPtrIfNoModule) {
|
|
|
|
LLVMContext Context;
|
|
|
|
// Even though the function is explicitly 4 byte aligned, in the absence of a
|
|
|
|
// DataLayout we can't assume that the function pointer is aligned.
|
2019-10-15 13:24:36 +02:00
|
|
|
ASSERT_FALSE(foldFuncPtrAndConstToNull(Context, nullptr, 2, Align(4)));
|
2019-03-08 11:44:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConstantsTest, FoldGlobalVariablePtr) {
|
|
|
|
LLVMContext Context;
|
|
|
|
|
|
|
|
IntegerType *IntType(Type::getInt32Ty(Context));
|
|
|
|
|
|
|
|
std::unique_ptr<GlobalVariable> Global(
|
|
|
|
new GlobalVariable(IntType, true, GlobalValue::ExternalLinkage));
|
|
|
|
|
2019-10-15 13:24:36 +02:00
|
|
|
Global->setAlignment(Align(4));
|
2019-03-08 11:44:06 +01:00
|
|
|
|
|
|
|
ConstantInt *TheConstant(ConstantInt::get(IntType, 2));
|
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
Constant *TheConstantExpr(ConstantExpr::getPtrToInt(Global.get(), IntType));
|
2019-03-08 11:44:06 +01:00
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
ASSERT_TRUE(ConstantExpr::get(Instruction::And, TheConstantExpr, TheConstant)
|
|
|
|
->isNullValue());
|
2019-03-08 11:44:06 +01:00
|
|
|
}
|
|
|
|
|
2021-01-05 02:09:49 +01:00
|
|
|
// Check that containsUndefOrPoisonElement and containsPoisonElement is working
|
|
|
|
// great
|
|
|
|
|
|
|
|
TEST(ConstantsTest, containsUndefElemTest) {
|
|
|
|
LLVMContext Context;
|
|
|
|
|
|
|
|
Type *Int32Ty = Type::getInt32Ty(Context);
|
|
|
|
Constant *CU = UndefValue::get(Int32Ty);
|
|
|
|
Constant *CP = PoisonValue::get(Int32Ty);
|
|
|
|
Constant *C1 = ConstantInt::get(Int32Ty, 1);
|
|
|
|
Constant *C2 = ConstantInt::get(Int32Ty, 2);
|
|
|
|
|
|
|
|
{
|
|
|
|
Constant *V1 = ConstantVector::get({C1, C2});
|
|
|
|
EXPECT_FALSE(V1->containsUndefOrPoisonElement());
|
|
|
|
EXPECT_FALSE(V1->containsPoisonElement());
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Constant *V2 = ConstantVector::get({C1, CU});
|
|
|
|
EXPECT_TRUE(V2->containsUndefOrPoisonElement());
|
|
|
|
EXPECT_FALSE(V2->containsPoisonElement());
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Constant *V3 = ConstantVector::get({C1, CP});
|
|
|
|
EXPECT_TRUE(V3->containsUndefOrPoisonElement());
|
|
|
|
EXPECT_TRUE(V3->containsPoisonElement());
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Constant *V4 = ConstantVector::get({CU, CP});
|
|
|
|
EXPECT_TRUE(V4->containsUndefOrPoisonElement());
|
|
|
|
EXPECT_TRUE(V4->containsPoisonElement());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-14 17:47:22 +01:00
|
|
|
// Check that undefined elements in vector constants are matched
|
2020-01-16 22:20:48 +01:00
|
|
|
// correctly for both integer and floating-point types. Just don't
|
|
|
|
// crash on vectors of pointers (could be handled?).
|
2020-01-14 17:47:22 +01:00
|
|
|
|
|
|
|
TEST(ConstantsTest, isElementWiseEqual) {
|
|
|
|
LLVMContext Context;
|
|
|
|
|
|
|
|
Type *Int32Ty = Type::getInt32Ty(Context);
|
|
|
|
Constant *CU = UndefValue::get(Int32Ty);
|
|
|
|
Constant *C1 = ConstantInt::get(Int32Ty, 1);
|
|
|
|
Constant *C2 = ConstantInt::get(Int32Ty, 2);
|
|
|
|
|
|
|
|
Constant *C1211 = ConstantVector::get({C1, C2, C1, C1});
|
|
|
|
Constant *C12U1 = ConstantVector::get({C1, C2, CU, C1});
|
|
|
|
Constant *C12U2 = ConstantVector::get({C1, C2, CU, C2});
|
|
|
|
Constant *C12U21 = ConstantVector::get({C1, C2, CU, C2, C1});
|
|
|
|
|
|
|
|
EXPECT_TRUE(C1211->isElementWiseEqual(C12U1));
|
|
|
|
EXPECT_TRUE(C12U1->isElementWiseEqual(C1211));
|
|
|
|
EXPECT_FALSE(C12U2->isElementWiseEqual(C12U1));
|
|
|
|
EXPECT_FALSE(C12U1->isElementWiseEqual(C12U2));
|
|
|
|
EXPECT_FALSE(C12U21->isElementWiseEqual(C12U2));
|
|
|
|
|
|
|
|
Type *FltTy = Type::getFloatTy(Context);
|
|
|
|
Constant *CFU = UndefValue::get(FltTy);
|
|
|
|
Constant *CF1 = ConstantFP::get(FltTy, 1.0);
|
|
|
|
Constant *CF2 = ConstantFP::get(FltTy, 2.0);
|
|
|
|
|
|
|
|
Constant *CF1211 = ConstantVector::get({CF1, CF2, CF1, CF1});
|
|
|
|
Constant *CF12U1 = ConstantVector::get({CF1, CF2, CFU, CF1});
|
|
|
|
Constant *CF12U2 = ConstantVector::get({CF1, CF2, CFU, CF2});
|
2020-01-17 14:25:15 +01:00
|
|
|
Constant *CFUU1U = ConstantVector::get({CFU, CFU, CF1, CFU});
|
2020-01-14 17:47:22 +01:00
|
|
|
|
|
|
|
EXPECT_TRUE(CF1211->isElementWiseEqual(CF12U1));
|
|
|
|
EXPECT_TRUE(CF12U1->isElementWiseEqual(CF1211));
|
2020-01-17 14:31:16 +01:00
|
|
|
EXPECT_TRUE(CFUU1U->isElementWiseEqual(CF12U1));
|
2020-01-14 17:47:22 +01:00
|
|
|
EXPECT_FALSE(CF12U2->isElementWiseEqual(CF12U1));
|
|
|
|
EXPECT_FALSE(CF12U1->isElementWiseEqual(CF12U2));
|
2020-01-16 22:20:48 +01:00
|
|
|
|
|
|
|
PointerType *PtrTy = Type::getInt8PtrTy(Context);
|
|
|
|
Constant *CPU = UndefValue::get(PtrTy);
|
|
|
|
Constant *CP0 = ConstantPointerNull::get(PtrTy);
|
|
|
|
|
|
|
|
Constant *CP0000 = ConstantVector::get({CP0, CP0, CP0, CP0});
|
|
|
|
Constant *CP00U0 = ConstantVector::get({CP0, CP0, CPU, CP0});
|
|
|
|
Constant *CP00U = ConstantVector::get({CP0, CP0, CPU});
|
|
|
|
|
|
|
|
EXPECT_FALSE(CP0000->isElementWiseEqual(CP00U0));
|
|
|
|
EXPECT_FALSE(CP00U0->isElementWiseEqual(CP0000));
|
|
|
|
EXPECT_FALSE(CP0000->isElementWiseEqual(CP00U));
|
|
|
|
EXPECT_FALSE(CP00U->isElementWiseEqual(CP00U0));
|
2020-01-14 17:47:22 +01:00
|
|
|
}
|
|
|
|
|
2021-04-08 08:20:08 +02:00
|
|
|
// Check that vector/aggregate constants correctly store undef and poison
|
|
|
|
// elements.
|
|
|
|
|
|
|
|
TEST(ConstantsTest, CheckElementWiseUndefPoison) {
|
|
|
|
LLVMContext Context;
|
|
|
|
|
|
|
|
Type *Int32Ty = Type::getInt32Ty(Context);
|
|
|
|
StructType *STy = StructType::get(Int32Ty, Int32Ty);
|
|
|
|
ArrayType *ATy = ArrayType::get(Int32Ty, 2);
|
|
|
|
Constant *CU = UndefValue::get(Int32Ty);
|
|
|
|
Constant *CP = PoisonValue::get(Int32Ty);
|
|
|
|
|
|
|
|
{
|
|
|
|
Constant *CUU = ConstantVector::get({CU, CU});
|
|
|
|
Constant *CPP = ConstantVector::get({CP, CP});
|
|
|
|
Constant *CUP = ConstantVector::get({CU, CP});
|
|
|
|
Constant *CPU = ConstantVector::get({CP, CU});
|
|
|
|
EXPECT_EQ(CUU, UndefValue::get(CUU->getType()));
|
|
|
|
EXPECT_EQ(CPP, PoisonValue::get(CPP->getType()));
|
|
|
|
EXPECT_NE(CUP, UndefValue::get(CUP->getType()));
|
|
|
|
EXPECT_NE(CPU, UndefValue::get(CPU->getType()));
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Constant *CUU = ConstantStruct::get(STy, {CU, CU});
|
|
|
|
Constant *CPP = ConstantStruct::get(STy, {CP, CP});
|
|
|
|
Constant *CUP = ConstantStruct::get(STy, {CU, CP});
|
|
|
|
Constant *CPU = ConstantStruct::get(STy, {CP, CU});
|
|
|
|
EXPECT_EQ(CUU, UndefValue::get(CUU->getType()));
|
|
|
|
EXPECT_EQ(CPP, PoisonValue::get(CPP->getType()));
|
|
|
|
EXPECT_NE(CUP, UndefValue::get(CUP->getType()));
|
|
|
|
EXPECT_NE(CPU, UndefValue::get(CPU->getType()));
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Constant *CUU = ConstantArray::get(ATy, {CU, CU});
|
|
|
|
Constant *CPP = ConstantArray::get(ATy, {CP, CP});
|
|
|
|
Constant *CUP = ConstantArray::get(ATy, {CU, CP});
|
|
|
|
Constant *CPU = ConstantArray::get(ATy, {CP, CU});
|
|
|
|
EXPECT_EQ(CUU, UndefValue::get(CUU->getType()));
|
|
|
|
EXPECT_EQ(CPP, PoisonValue::get(CPP->getType()));
|
|
|
|
EXPECT_NE(CUP, UndefValue::get(CUP->getType()));
|
|
|
|
EXPECT_NE(CPU, UndefValue::get(CPU->getType()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-07 22:16:00 +02:00
|
|
|
TEST(ConstantsTest, GetSplatValueRoundTrip) {
|
|
|
|
LLVMContext Context;
|
|
|
|
|
|
|
|
Type *FloatTy = Type::getFloatTy(Context);
|
|
|
|
Type *Int32Ty = Type::getInt32Ty(Context);
|
|
|
|
Type *Int8Ty = Type::getInt8Ty(Context);
|
|
|
|
|
|
|
|
for (unsigned Min : {1, 2, 8}) {
|
2020-08-19 19:26:36 +02:00
|
|
|
auto ScalableEC = ElementCount::getScalable(Min);
|
|
|
|
auto FixedEC = ElementCount::getFixed(Min);
|
2020-07-07 22:16:00 +02:00
|
|
|
|
2020-07-08 21:11:42 +02:00
|
|
|
for (auto EC : {ScalableEC, FixedEC}) {
|
2020-07-07 22:16:00 +02:00
|
|
|
for (auto *Ty : {FloatTy, Int32Ty, Int8Ty}) {
|
|
|
|
Constant *Zero = Constant::getNullValue(Ty);
|
|
|
|
Constant *One = Constant::getAllOnesValue(Ty);
|
|
|
|
|
|
|
|
for (auto *C : {Zero, One}) {
|
|
|
|
Constant *Splat = ConstantVector::getSplat(EC, C);
|
|
|
|
ASSERT_NE(nullptr, Splat);
|
|
|
|
|
|
|
|
Constant *SplatVal = Splat->getSplatValue();
|
|
|
|
EXPECT_NE(nullptr, SplatVal);
|
|
|
|
EXPECT_EQ(SplatVal, C);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-15 22:26:39 +01:00
|
|
|
} // end anonymous namespace
|
|
|
|
} // end namespace llvm
|