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"
|
2021-04-19 17:31:41 +08:00
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
2013-04-12 16:33:11 +08:00
|
|
|
#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);
|
|
|
|
|
The maximal representable alignment in LLVM IR is 1GiB, not 512MiB
In LLVM IR, `AlignmentBitfieldElementT` is 5-bit wide
But that means that the maximal alignment exponent is `(1<<5)-2`,
which is `30`, not `29`. And indeed, alignment of `1073741824`
roundtrips IR serialization-deserialization.
While this doesn't seem all that important, this doubles
the maximal supported alignment from 512MiB to 1GiB,
and there's actually one noticeable use-case for that;
On X86, the huge pages can have sizes of 2MiB and 1GiB (!).
So while this doesn't add support for truly huge alignments,
which i think we can easily-ish do if wanted, i think this adds
zero-cost support for a not-trivially-dismissable case.
I don't believe we need any upgrade infrastructure,
and since we don't explicitly record the IR version,
we don't need to bump one either.
As @craig.topper speculates in D108661#2963519,
this might be an artificial limit imposed by the original implementation
of the `getAlignment()` functions.
Differential Revision: https://reviews.llvm.org/D108661
2021-08-26 16:51:28 +08:00
|
|
|
EXPECT_TRUE(Value::MaximumAlignment == 1073741824U);
|
|
|
|
Dummy0->setAlignment(Align(1073741824));
|
|
|
|
EXPECT_EQ(Dummy0->getAlignment(), 1073741824U);
|
2014-10-23 22:45:19 +08:00
|
|
|
|
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);
|
|
|
|
|
The maximal representable alignment in LLVM IR is 1GiB, not 512MiB
In LLVM IR, `AlignmentBitfieldElementT` is 5-bit wide
But that means that the maximal alignment exponent is `(1<<5)-2`,
which is `30`, not `29`. And indeed, alignment of `1073741824`
roundtrips IR serialization-deserialization.
While this doesn't seem all that important, this doubles
the maximal supported alignment from 512MiB to 1GiB,
and there's actually one noticeable use-case for that;
On X86, the huge pages can have sizes of 2MiB and 1GiB (!).
So while this doesn't add support for truly huge alignments,
which i think we can easily-ish do if wanted, i think this adds
zero-cost support for a not-trivially-dismissable case.
I don't believe we need any upgrade infrastructure,
and since we don't explicitly record the IR version,
we don't need to bump one either.
As @craig.topper speculates in D108661#2963519,
this might be an artificial limit imposed by the original implementation
of the `getAlignment()` functions.
Differential Revision: https://reviews.llvm.org/D108661
2021-08-26 16:51:28 +08:00
|
|
|
EXPECT_DEATH(Var->setAlignment(Align(2147483648U)),
|
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
|
|
|
|
|
2021-04-19 17:31:41 +08:00
|
|
|
TEST(ValueTest, replaceUsesOutsideBlock) {
|
|
|
|
// Check that Value::replaceUsesOutsideBlock(New, BB) replaces uses outside
|
|
|
|
// BB, including dbg.* uses of MetadataAsValue(ValueAsMetadata(this)).
|
|
|
|
const auto *IR = R"(
|
|
|
|
define i32 @f() !dbg !6 {
|
|
|
|
entry:
|
|
|
|
%a = add i32 0, 1, !dbg !15
|
|
|
|
%b = add i32 0, 2, !dbg !15
|
|
|
|
%c = add i32 %a, 2, !dbg !15
|
|
|
|
call void @llvm.dbg.value(metadata i32 %a, metadata !9, metadata !DIExpression()), !dbg !15
|
|
|
|
br label %exit, !dbg !15
|
|
|
|
|
|
|
|
exit:
|
|
|
|
call void @llvm.dbg.value(metadata i32 %a, metadata !11, metadata !DIExpression()), !dbg !16
|
|
|
|
ret i32 %a, !dbg !16
|
|
|
|
}
|
|
|
|
|
|
|
|
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
|
|
|
|
|
|
|
!llvm.dbg.cu = !{!0}
|
|
|
|
!llvm.module.flags = !{!5}
|
|
|
|
|
|
|
|
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
|
|
|
!1 = !DIFile(filename: "test.ll", directory: "/")
|
|
|
|
!2 = !{}
|
|
|
|
!5 = !{i32 2, !"Debug Info Version", i32 3}
|
|
|
|
!6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !8)
|
|
|
|
!7 = !DISubroutineType(types: !2)
|
|
|
|
!8 = !{!9, !11}
|
|
|
|
!9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
|
|
|
|
!10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_signed)
|
|
|
|
!11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !12)
|
|
|
|
!12 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_signed)
|
|
|
|
!15 = !DILocation(line: 1, column: 1, scope: !6)
|
|
|
|
!16 = !DILocation(line: 5, column: 1, scope: !6)
|
|
|
|
)";
|
|
|
|
LLVMContext Ctx;
|
|
|
|
SMDiagnostic Err;
|
|
|
|
std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx);
|
|
|
|
if (!M)
|
|
|
|
Err.print("ValueTest", errs());
|
|
|
|
|
|
|
|
auto GetNext = [](auto *I) { return &*++I->getIterator(); };
|
|
|
|
|
|
|
|
Function *F = M->getFunction("f");
|
|
|
|
// Entry.
|
|
|
|
BasicBlock *Entry = &F->front();
|
|
|
|
Instruction *A = &Entry->front();
|
|
|
|
Instruction *B = GetNext(A);
|
|
|
|
Instruction *C = GetNext(B);
|
|
|
|
auto *EntryDbg = cast<DbgValueInst>(GetNext(C));
|
|
|
|
// Exit.
|
|
|
|
BasicBlock *Exit = GetNext(Entry);
|
|
|
|
auto *ExitDbg = cast<DbgValueInst>(&Exit->front());
|
|
|
|
Instruction *Ret = GetNext(ExitDbg);
|
|
|
|
|
|
|
|
A->replaceUsesOutsideBlock(B, Entry);
|
|
|
|
// These users are in Entry so shouldn't be changed.
|
|
|
|
ASSERT_TRUE(C->getOperand(0) == cast<Value>(A));
|
|
|
|
ASSERT_TRUE(EntryDbg->getValue(0) == cast<Value>(A));
|
|
|
|
// These users are outside Entry so should be changed.
|
|
|
|
ASSERT_TRUE(ExitDbg->getValue(0) == cast<Value>(B));
|
|
|
|
ASSERT_TRUE(Ret->getOperand(0) == cast<Value>(B));
|
|
|
|
}
|
2013-04-12 16:33:11 +08:00
|
|
|
} // end anonymous namespace
|