2013-04-12 16:33:11 +08:00
|
|
|
//===- llvm/unittest/IR/ValueTest.cpp - Value unit tests ------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08: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
|
2013-04-12 16:33:11 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-06 19:06:56 +08:00
|
|
|
#include "llvm/IR/Value.h"
|
2014-01-07 20:34:26 +08:00
|
|
|
#include "llvm/AsmParser/Parser.h"
|
2013-04-12 16:33:11 +08:00
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
2015-06-27 08:38:26 +08:00
|
|
|
#include "llvm/IR/ModuleSlotTracker.h"
|
2013-04-12 16:33:11 +08:00
|
|
|
#include "llvm/Support/SourceMgr.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
TEST(ValueTest, UsedInBasicBlock) {
|
|
|
|
LLVMContext C;
|
|
|
|
|
|
|
|
const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n"
|
|
|
|
"bb0:\n"
|
|
|
|
" %y1 = add i32 %y, 1\n"
|
|
|
|
" %y2 = add i32 %y, 1\n"
|
|
|
|
" %y3 = add i32 %y, 1\n"
|
|
|
|
" %y4 = add i32 %y, 1\n"
|
|
|
|
" %y5 = add i32 %y, 1\n"
|
|
|
|
" %y6 = add i32 %y, 1\n"
|
|
|
|
" %y7 = add i32 %y, 1\n"
|
|
|
|
" %y8 = add i32 %x, 1\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n";
|
|
|
|
SMDiagnostic Err;
|
2014-08-20 00:58:54 +08:00
|
|
|
std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C);
|
2013-04-12 16:33:11 +08:00
|
|
|
|
|
|
|
Function *F = M->getFunction("f");
|
|
|
|
|
2015-10-21 02:30:20 +08:00
|
|
|
EXPECT_FALSE(F->isUsedInBasicBlock(&F->front()));
|
Remove getArgumentList() in favor of arg_begin(), args(), etc
Users often call getArgumentList().size(), which is a linear way to get
the number of function arguments. arg_size(), on the other hand, is
constant time.
In general, the fact that arguments are stored in an iplist is an
implementation detail, so I've removed it from the Function interface
and moved all other users to the argument container APIs (arg_begin(),
arg_end(), args(), arg_size()).
Reviewed By: chandlerc
Differential Revision: https://reviews.llvm.org/D31052
llvm-svn: 298010
2017-03-17 06:59:15 +08:00
|
|
|
EXPECT_TRUE(std::next(F->arg_begin())->isUsedInBasicBlock(&F->front()));
|
2015-10-21 02:30:20 +08:00
|
|
|
EXPECT_TRUE(F->arg_begin()->isUsedInBasicBlock(&F->front()));
|
2013-04-12 16:33:11 +08:00
|
|
|
}
|
|
|
|
|
2013-10-01 05:23:03 +08:00
|
|
|
TEST(GlobalTest, CreateAddressSpace) {
|
2016-04-15 05:59:01 +08:00
|
|
|
LLVMContext Ctx;
|
2014-03-06 13:51:42 +08:00
|
|
|
std::unique_ptr<Module> M(new Module("TestModule", Ctx));
|
2013-10-01 05:23:03 +08:00
|
|
|
Type *Int8Ty = Type::getInt8Ty(Ctx);
|
|
|
|
Type *Int32Ty = Type::getInt32Ty(Ctx);
|
|
|
|
|
|
|
|
GlobalVariable *Dummy0
|
|
|
|
= new GlobalVariable(*M,
|
|
|
|
Int32Ty,
|
|
|
|
true,
|
|
|
|
GlobalValue::ExternalLinkage,
|
|
|
|
Constant::getAllOnesValue(Int32Ty),
|
|
|
|
"dummy",
|
2014-06-09 06:29:17 +08:00
|
|
|
nullptr,
|
2013-10-01 05:23:03 +08:00
|
|
|
GlobalVariable::NotThreadLocal,
|
|
|
|
1);
|
|
|
|
|
2014-10-23 22:45:19 +08:00
|
|
|
EXPECT_TRUE(Value::MaximumAlignment == 536870912U);
|
2019-10-15 19:24:36 +08:00
|
|
|
Dummy0->setAlignment(Align(536870912));
|
2014-10-23 22:45:19 +08:00
|
|
|
EXPECT_EQ(Dummy0->getAlignment(), 536870912U);
|
|
|
|
|
2013-10-01 05:23:03 +08:00
|
|
|
// Make sure the address space isn't dropped when returning this.
|
|
|
|
Constant *Dummy1 = M->getOrInsertGlobal("dummy", Int32Ty);
|
|
|
|
EXPECT_EQ(Dummy0, Dummy1);
|
|
|
|
EXPECT_EQ(1u, Dummy1->getType()->getPointerAddressSpace());
|
|
|
|
|
|
|
|
|
|
|
|
// This one requires a bitcast, but the address space must also stay the same.
|
|
|
|
GlobalVariable *DummyCast0
|
|
|
|
= new GlobalVariable(*M,
|
|
|
|
Int32Ty,
|
|
|
|
true,
|
|
|
|
GlobalValue::ExternalLinkage,
|
|
|
|
Constant::getAllOnesValue(Int32Ty),
|
|
|
|
"dummy_cast",
|
2014-06-09 06:29:17 +08:00
|
|
|
nullptr,
|
2013-10-01 05:23:03 +08:00
|
|
|
GlobalVariable::NotThreadLocal,
|
|
|
|
1);
|
|
|
|
|
|
|
|
// Make sure the address space isn't dropped when returning this.
|
|
|
|
Constant *DummyCast1 = M->getOrInsertGlobal("dummy_cast", Int8Ty);
|
|
|
|
EXPECT_EQ(1u, DummyCast1->getType()->getPointerAddressSpace());
|
|
|
|
EXPECT_NE(DummyCast0, DummyCast1) << *DummyCast1;
|
|
|
|
}
|
2014-10-23 22:45:19 +08:00
|
|
|
|
|
|
|
#ifdef GTEST_HAS_DEATH_TEST
|
|
|
|
#ifndef NDEBUG
|
2019-10-15 19:24:36 +08:00
|
|
|
|
2014-10-23 22:45:19 +08:00
|
|
|
TEST(GlobalTest, AlignDeath) {
|
2016-04-15 05:59:01 +08:00
|
|
|
LLVMContext Ctx;
|
2014-10-23 22:45:19 +08:00
|
|
|
std::unique_ptr<Module> M(new Module("TestModule", Ctx));
|
|
|
|
Type *Int32Ty = Type::getInt32Ty(Ctx);
|
|
|
|
GlobalVariable *Var =
|
|
|
|
new GlobalVariable(*M, Int32Ty, true, GlobalValue::ExternalLinkage,
|
|
|
|
Constant::getAllOnesValue(Int32Ty), "var", nullptr,
|
|
|
|
GlobalVariable::NotThreadLocal, 1);
|
|
|
|
|
2019-10-15 19:24:36 +08:00
|
|
|
EXPECT_DEATH(Var->setAlignment(Align(1073741824U)),
|
2014-10-23 22:45:19 +08:00
|
|
|
"Alignment is greater than MaximumAlignment");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2015-06-27 08:38:26 +08:00
|
|
|
TEST(ValueTest, printSlots) {
|
|
|
|
// Check that Value::print() and Value::printAsOperand() work with and
|
|
|
|
// without a slot tracker.
|
|
|
|
LLVMContext C;
|
|
|
|
|
[MIR] Making MIR Printing, opt -dot-cfg, and -debug printing faster
Value::printAsOperand has been scanning the entire module just to
print a single value as an operand, regardless being asked to print a
type or not at all, and regardless really needing to scan the module
to print a type.
It made some of the users of the method exceptionally slow on large
IR-modules (or large MIR-files with large IR-modules embedded).
This patch defers scanning a module looking for struct types, mostly
numbered struct types, as much as possible, speeding up those users
w/o changing any APIs at all.
See speedup examples below:
Release Build:
# 83 seconds -> 5.5 seconds
time ./bin/llc -start-before=irtranslator -stop-after=irtranslator \
-global-isel -global-isel-abort=2 -simplify-mir sqlite3.O0.ll -o \
sqlite3.O0.ll.regbankselected.mir
# 133 seconds -> 6.2 seconds
time ./bin/opt sqlite3.O0.ll -dot-cfg -disable-output
Release + Asserts Build:
# 95 seconds -> 5.5 seconds
time ./bin/llc -start-before=irtranslator -stop-after=irtranslator \
-global-isel -global-isel-abort=2 -simplify-mir sqlite3.O0.ll -o \
sqlite3.O0.ll.regbankselected.mir
# 146 seconds -> 6.2 seconds
time ./bin/opt sqlite3.O0.ll -dot-cfg -disable-output
# 1096 seconds -> 553 seconds
time ./bin/llc -debug-only=isel -fast-isel=false -stop-after=isel \
sqlite3.O0.ll -o /dev/null 2> err
where sqlite3.O0.ll is non-optimized IR produced from
sqlite-amalgamation (http://sqlite.org/download.html), which is entire
SQLite3 implementation in a single C-file.
Benchmarked on 4-cores / 8 threads PCI-E SSD iMac running macOS
Reviewers: dexonsmith, bkramer, void, chandlerc, aditya_nandakumar, dsanders, qcolombet,
Reviewed By: bogner
Subscribers: thegameg, llvm-commits
Differential Revision: https://reviews.llvm.org/D44132
llvm-svn: 328246
2018-03-23 05:29:07 +08:00
|
|
|
const char *ModuleString = "@g0 = external global %500\n"
|
|
|
|
"@g1 = external global %900\n"
|
|
|
|
"\n"
|
|
|
|
"%900 = type { i32, i32 }\n"
|
|
|
|
"%500 = type { i32 }\n"
|
|
|
|
"\n"
|
|
|
|
"define void @f(i32 %x, i32 %y) {\n"
|
2015-06-27 08:38:26 +08:00
|
|
|
"entry:\n"
|
|
|
|
" %0 = add i32 %y, 1\n"
|
|
|
|
" %1 = add i32 %y, 1\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n";
|
|
|
|
SMDiagnostic Err;
|
|
|
|
std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C);
|
|
|
|
|
|
|
|
Function *F = M->getFunction("f");
|
|
|
|
ASSERT_TRUE(F);
|
|
|
|
ASSERT_FALSE(F->empty());
|
|
|
|
BasicBlock &BB = F->getEntryBlock();
|
|
|
|
ASSERT_EQ(3u, BB.size());
|
|
|
|
|
2015-10-21 02:30:20 +08:00
|
|
|
Instruction *I0 = &*BB.begin();
|
2015-06-27 08:38:26 +08:00
|
|
|
ASSERT_TRUE(I0);
|
2015-10-21 02:30:20 +08:00
|
|
|
Instruction *I1 = &*++BB.begin();
|
2015-06-27 08:38:26 +08:00
|
|
|
ASSERT_TRUE(I1);
|
|
|
|
|
[MIR] Making MIR Printing, opt -dot-cfg, and -debug printing faster
Value::printAsOperand has been scanning the entire module just to
print a single value as an operand, regardless being asked to print a
type or not at all, and regardless really needing to scan the module
to print a type.
It made some of the users of the method exceptionally slow on large
IR-modules (or large MIR-files with large IR-modules embedded).
This patch defers scanning a module looking for struct types, mostly
numbered struct types, as much as possible, speeding up those users
w/o changing any APIs at all.
See speedup examples below:
Release Build:
# 83 seconds -> 5.5 seconds
time ./bin/llc -start-before=irtranslator -stop-after=irtranslator \
-global-isel -global-isel-abort=2 -simplify-mir sqlite3.O0.ll -o \
sqlite3.O0.ll.regbankselected.mir
# 133 seconds -> 6.2 seconds
time ./bin/opt sqlite3.O0.ll -dot-cfg -disable-output
Release + Asserts Build:
# 95 seconds -> 5.5 seconds
time ./bin/llc -start-before=irtranslator -stop-after=irtranslator \
-global-isel -global-isel-abort=2 -simplify-mir sqlite3.O0.ll -o \
sqlite3.O0.ll.regbankselected.mir
# 146 seconds -> 6.2 seconds
time ./bin/opt sqlite3.O0.ll -dot-cfg -disable-output
# 1096 seconds -> 553 seconds
time ./bin/llc -debug-only=isel -fast-isel=false -stop-after=isel \
sqlite3.O0.ll -o /dev/null 2> err
where sqlite3.O0.ll is non-optimized IR produced from
sqlite-amalgamation (http://sqlite.org/download.html), which is entire
SQLite3 implementation in a single C-file.
Benchmarked on 4-cores / 8 threads PCI-E SSD iMac running macOS
Reviewers: dexonsmith, bkramer, void, chandlerc, aditya_nandakumar, dsanders, qcolombet,
Reviewed By: bogner
Subscribers: thegameg, llvm-commits
Differential Revision: https://reviews.llvm.org/D44132
llvm-svn: 328246
2018-03-23 05:29:07 +08:00
|
|
|
GlobalVariable *G0 = M->getGlobalVariable("g0");
|
|
|
|
ASSERT_TRUE(G0);
|
|
|
|
GlobalVariable *G1 = M->getGlobalVariable("g1");
|
|
|
|
ASSERT_TRUE(G1);
|
|
|
|
|
2015-06-27 08:38:26 +08:00
|
|
|
ModuleSlotTracker MST(M.get());
|
|
|
|
|
|
|
|
#define CHECK_PRINT(INST, STR) \
|
|
|
|
do { \
|
|
|
|
{ \
|
|
|
|
std::string S; \
|
|
|
|
raw_string_ostream OS(S); \
|
|
|
|
INST->print(OS); \
|
|
|
|
EXPECT_EQ(STR, OS.str()); \
|
|
|
|
} \
|
|
|
|
{ \
|
|
|
|
std::string S; \
|
|
|
|
raw_string_ostream OS(S); \
|
|
|
|
INST->print(OS, MST); \
|
|
|
|
EXPECT_EQ(STR, OS.str()); \
|
|
|
|
} \
|
|
|
|
} while (false)
|
|
|
|
CHECK_PRINT(I0, " %0 = add i32 %y, 1");
|
|
|
|
CHECK_PRINT(I1, " %1 = add i32 %y, 1");
|
|
|
|
#undef CHECK_PRINT
|
|
|
|
|
|
|
|
#define CHECK_PRINT_AS_OPERAND(INST, TYPE, STR) \
|
|
|
|
do { \
|
|
|
|
{ \
|
|
|
|
std::string S; \
|
|
|
|
raw_string_ostream OS(S); \
|
|
|
|
INST->printAsOperand(OS, TYPE); \
|
|
|
|
EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \
|
|
|
|
} \
|
|
|
|
{ \
|
|
|
|
std::string S; \
|
|
|
|
raw_string_ostream OS(S); \
|
|
|
|
INST->printAsOperand(OS, TYPE, MST); \
|
|
|
|
EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \
|
|
|
|
} \
|
|
|
|
} while (false)
|
|
|
|
CHECK_PRINT_AS_OPERAND(I0, false, "%0");
|
|
|
|
CHECK_PRINT_AS_OPERAND(I1, false, "%1");
|
|
|
|
CHECK_PRINT_AS_OPERAND(I0, true, "i32 %0");
|
|
|
|
CHECK_PRINT_AS_OPERAND(I1, true, "i32 %1");
|
[MIR] Making MIR Printing, opt -dot-cfg, and -debug printing faster
Value::printAsOperand has been scanning the entire module just to
print a single value as an operand, regardless being asked to print a
type or not at all, and regardless really needing to scan the module
to print a type.
It made some of the users of the method exceptionally slow on large
IR-modules (or large MIR-files with large IR-modules embedded).
This patch defers scanning a module looking for struct types, mostly
numbered struct types, as much as possible, speeding up those users
w/o changing any APIs at all.
See speedup examples below:
Release Build:
# 83 seconds -> 5.5 seconds
time ./bin/llc -start-before=irtranslator -stop-after=irtranslator \
-global-isel -global-isel-abort=2 -simplify-mir sqlite3.O0.ll -o \
sqlite3.O0.ll.regbankselected.mir
# 133 seconds -> 6.2 seconds
time ./bin/opt sqlite3.O0.ll -dot-cfg -disable-output
Release + Asserts Build:
# 95 seconds -> 5.5 seconds
time ./bin/llc -start-before=irtranslator -stop-after=irtranslator \
-global-isel -global-isel-abort=2 -simplify-mir sqlite3.O0.ll -o \
sqlite3.O0.ll.regbankselected.mir
# 146 seconds -> 6.2 seconds
time ./bin/opt sqlite3.O0.ll -dot-cfg -disable-output
# 1096 seconds -> 553 seconds
time ./bin/llc -debug-only=isel -fast-isel=false -stop-after=isel \
sqlite3.O0.ll -o /dev/null 2> err
where sqlite3.O0.ll is non-optimized IR produced from
sqlite-amalgamation (http://sqlite.org/download.html), which is entire
SQLite3 implementation in a single C-file.
Benchmarked on 4-cores / 8 threads PCI-E SSD iMac running macOS
Reviewers: dexonsmith, bkramer, void, chandlerc, aditya_nandakumar, dsanders, qcolombet,
Reviewed By: bogner
Subscribers: thegameg, llvm-commits
Differential Revision: https://reviews.llvm.org/D44132
llvm-svn: 328246
2018-03-23 05:29:07 +08:00
|
|
|
CHECK_PRINT_AS_OPERAND(G0, true, "%0* @g0");
|
|
|
|
CHECK_PRINT_AS_OPERAND(G1, true, "%1* @g1");
|
2015-06-27 08:38:26 +08:00
|
|
|
#undef CHECK_PRINT_AS_OPERAND
|
|
|
|
}
|
|
|
|
|
2015-07-28 06:31:04 +08:00
|
|
|
TEST(ValueTest, getLocalSlots) {
|
|
|
|
// Verify that the getLocalSlot method returns the correct slot numbers.
|
|
|
|
LLVMContext C;
|
|
|
|
const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n"
|
|
|
|
"entry:\n"
|
|
|
|
" %0 = add i32 %y, 1\n"
|
|
|
|
" %1 = add i32 %y, 1\n"
|
|
|
|
" br label %2\n"
|
|
|
|
"\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n";
|
|
|
|
SMDiagnostic Err;
|
|
|
|
std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C);
|
|
|
|
|
|
|
|
Function *F = M->getFunction("f");
|
|
|
|
ASSERT_TRUE(F);
|
|
|
|
ASSERT_FALSE(F->empty());
|
|
|
|
BasicBlock &EntryBB = F->getEntryBlock();
|
|
|
|
ASSERT_EQ(3u, EntryBB.size());
|
2015-10-21 02:30:20 +08:00
|
|
|
BasicBlock *BB2 = &*++F->begin();
|
2015-07-28 06:31:04 +08:00
|
|
|
ASSERT_TRUE(BB2);
|
|
|
|
|
2015-10-21 02:30:20 +08:00
|
|
|
Instruction *I0 = &*EntryBB.begin();
|
2015-07-28 06:31:04 +08:00
|
|
|
ASSERT_TRUE(I0);
|
2015-10-21 02:30:20 +08:00
|
|
|
Instruction *I1 = &*++EntryBB.begin();
|
2015-07-28 06:31:04 +08:00
|
|
|
ASSERT_TRUE(I1);
|
|
|
|
|
|
|
|
ModuleSlotTracker MST(M.get());
|
|
|
|
MST.incorporateFunction(*F);
|
|
|
|
EXPECT_EQ(MST.getLocalSlot(I0), 0);
|
|
|
|
EXPECT_EQ(MST.getLocalSlot(I1), 1);
|
|
|
|
EXPECT_EQ(MST.getLocalSlot(&EntryBB), -1);
|
|
|
|
EXPECT_EQ(MST.getLocalSlot(BB2), 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
|
|
|
|
TEST(ValueTest, getLocalSlotDeath) {
|
|
|
|
LLVMContext C;
|
|
|
|
const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n"
|
|
|
|
"entry:\n"
|
|
|
|
" %0 = add i32 %y, 1\n"
|
|
|
|
" %1 = add i32 %y, 1\n"
|
|
|
|
" br label %2\n"
|
|
|
|
"\n"
|
|
|
|
" ret void\n"
|
|
|
|
"}\n";
|
|
|
|
SMDiagnostic Err;
|
|
|
|
std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C);
|
|
|
|
|
|
|
|
Function *F = M->getFunction("f");
|
|
|
|
ASSERT_TRUE(F);
|
|
|
|
ASSERT_FALSE(F->empty());
|
2015-10-21 02:30:20 +08:00
|
|
|
BasicBlock *BB2 = &*++F->begin();
|
2015-07-28 06:31:04 +08:00
|
|
|
ASSERT_TRUE(BB2);
|
|
|
|
|
|
|
|
ModuleSlotTracker MST(M.get());
|
|
|
|
EXPECT_DEATH(MST.getLocalSlot(BB2), "No function incorporated");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-04-12 16:33:11 +08:00
|
|
|
} // end anonymous namespace
|