f
- float
+ float
f(
- int
+ int
P)
From 000ba715ddbd2a7af17534105f8a0916d4168c3e Mon Sep 17 00:00:00 2001
From: Jan Korous
Date: Fri, 12 Jul 2019 22:25:17 +0000
Subject: [PATCH 005/451] [DirectoryWatcher][NFC] Silence warnings in release
build
llvm-svn: 365968
---
.../linux/DirectoryWatcher-linux.cpp | 5 ++++-
.../DirectoryWatcher/DirectoryWatcherTest.cpp | 13 ++++++++++---
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
index 87d133f46d8e8..0c9f799b638d6 100644
--- a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
+++ b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
@@ -55,7 +55,10 @@ struct SemaphorePipe {
};
void signal() {
- ssize_t Result = llvm::sys::RetryAfterSignal(-1, write, FDWrite, "A", 1);
+#ifndef NDEBUG
+ ssize_t Result =
+#endif
+ llvm::sys::RetryAfterSignal(-1, write, FDWrite, "A", 1);
assert(Result != -1);
}
~SemaphorePipe() {
diff --git a/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp b/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp
index a2c50fc7d000f..0808ff47dee89 100644
--- a/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp
+++ b/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp
@@ -38,12 +38,18 @@ struct DirectoryWatcherTestFixture {
DirectoryWatcherTestFixture() {
SmallString<128> pathBuf;
- std::error_code UniqDirRes = createUniqueDirectory("dirwatcher", pathBuf);
+#ifndef NDEBUG
+ std::error_code UniqDirRes =
+#endif
+ createUniqueDirectory("dirwatcher", pathBuf);
assert(!UniqDirRes);
TestRootDir = pathBuf.str();
path::append(pathBuf, "watch");
TestWatchedDir = pathBuf.str();
- std::error_code CreateDirRes = create_directory(TestWatchedDir, false);
+#ifndef NDEBUG
+ std::error_code CreateDirRes =
+#endif
+ create_directory(TestWatchedDir, false);
assert(!CreateDirRes);
}
@@ -415,8 +421,9 @@ TEST(DirectoryWatcherTest, ChangeMetadata) {
const int FD = HopefullyTheFD.get();
const TimePoint<> NewTimePt =
std::chrono::system_clock::now() - std::chrono::minutes(1);
-
+#ifndef NDEBUG
std::error_code setTimeRes =
+#endif
llvm::sys::fs::setLastAccessAndModificationTime(FD, NewTimePt,
NewTimePt);
assert(!setTimeRes);
From 9178b10163f758cbf8a5290ea6a827990427ddc0 Mon Sep 17 00:00:00 2001
From: Alex Lorenz
Date: Fri, 12 Jul 2019 22:29:44 +0000
Subject: [PATCH 006/451] NFC: utils/perf-training: Python 3 compatibility for
lit.cfg
The output of subprocess.check_output is now bytes. We need to decode it.
llvm-svn: 365969
---
clang/utils/perf-training/lit.cfg | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/utils/perf-training/lit.cfg b/clang/utils/perf-training/lit.cfg
index 671d44f83b948..be822d66e38ce 100644
--- a/clang/utils/perf-training/lit.cfg
+++ b/clang/utils/perf-training/lit.cfg
@@ -10,7 +10,7 @@ def getSysrootFlagsOnDarwin(config, lit_config):
# default system root path.
if 'darwin' in config.target_triple:
try:
- out = subprocess.check_output(['xcrun', '--show-sdk-path']).strip()
+ out = subprocess.check_output(['xcrun', '--show-sdk-path']).strip().decode()
res = 0
except OSError:
res = -1
From db101864bdc938deb1d63fe4f7da761bd38e5cae Mon Sep 17 00:00:00 2001
From: Alina Sbirlea
Date: Fri, 12 Jul 2019 22:30:30 +0000
Subject: [PATCH 007/451] [MemorySSA] Use SetVector to avoid nondeterminism.
Summary:
Use a SetVector for DeadBlockSet.
Resolves PR42574.
Reviewers: george.burgess.iv, uabelho, dblaikie
Subscribers: jlebar, Prazek, mgrang, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D64601
llvm-svn: 365970
---
llvm/include/llvm/Analysis/MemorySSAUpdater.h | 3 +-
llvm/lib/Analysis/MemorySSAUpdater.cpp | 2 +-
.../lib/Transforms/Scalar/LoopSimplifyCFG.cpp | 4 +-
.../Transforms/Scalar/SimpleLoopUnswitch.cpp | 6 +-
llvm/lib/Transforms/Utils/Local.cpp | 2 +-
llvm/lib/Transforms/Utils/LoopSimplify.cpp | 3 +-
.../test/Analysis/MemorySSA/nondeterminism.ll | 122 ++++++++++++++++++
7 files changed, 133 insertions(+), 9 deletions(-)
create mode 100644 llvm/test/Analysis/MemorySSA/nondeterminism.ll
diff --git a/llvm/include/llvm/Analysis/MemorySSAUpdater.h b/llvm/include/llvm/Analysis/MemorySSAUpdater.h
index 6467d41cc0bf7..d4d8040c1ff66 100644
--- a/llvm/include/llvm/Analysis/MemorySSAUpdater.h
+++ b/llvm/include/llvm/Analysis/MemorySSAUpdater.h
@@ -31,6 +31,7 @@
#ifndef LLVM_ANALYSIS_MEMORYSSAUPDATER_H
#define LLVM_ANALYSIS_MEMORYSSAUPDATER_H
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -243,7 +244,7 @@ class MemorySSAUpdater {
/// Deleted blocks still have successor info, but their predecessor edges and
/// Phi nodes may already be updated. Instructions in DeadBlocks should be
/// deleted after this call.
- void removeBlocks(const SmallPtrSetImpl &DeadBlocks);
+ void removeBlocks(const SmallSetVector &DeadBlocks);
/// Instruction I will be changed to an unreachable. Remove all accesses in
/// I's block that follow I (inclusive), and update the Phis in the blocks'
diff --git a/llvm/lib/Analysis/MemorySSAUpdater.cpp b/llvm/lib/Analysis/MemorySSAUpdater.cpp
index 19559a62eb9ea..4c1feee7fd9af 100644
--- a/llvm/lib/Analysis/MemorySSAUpdater.cpp
+++ b/llvm/lib/Analysis/MemorySSAUpdater.cpp
@@ -1247,7 +1247,7 @@ void MemorySSAUpdater::removeMemoryAccess(MemoryAccess *MA, bool OptimizePhis) {
}
void MemorySSAUpdater::removeBlocks(
- const SmallPtrSetImpl &DeadBlocks) {
+ const SmallSetVector &DeadBlocks) {
// First delete all uses of BB in MemoryPhis.
for (BasicBlock *BB : DeadBlocks) {
Instruction *TI = BB->getTerminator();
diff --git a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
index c650abb412d9b..046f4c8af492e 100644
--- a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
@@ -428,8 +428,8 @@ class ConstantTerminatorFoldingImpl {
/// relevant updates to DT and LI.
void deleteDeadLoopBlocks() {
if (MSSAU) {
- SmallPtrSet DeadLoopBlocksSet(DeadLoopBlocks.begin(),
- DeadLoopBlocks.end());
+ SmallSetVector DeadLoopBlocksSet(DeadLoopBlocks.begin(),
+ DeadLoopBlocks.end());
MSSAU->removeBlocks(DeadLoopBlocksSet);
}
diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index 9715329223827..aeac6f548b32e 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -1463,8 +1463,8 @@ deleteDeadClonedBlocks(Loop &L, ArrayRef ExitBlocks,
// Remove all MemorySSA in the dead blocks
if (MSSAU) {
- SmallPtrSet DeadBlockSet(DeadBlocks.begin(),
- DeadBlocks.end());
+ SmallSetVector DeadBlockSet(DeadBlocks.begin(),
+ DeadBlocks.end());
MSSAU->removeBlocks(DeadBlockSet);
}
@@ -1482,7 +1482,7 @@ static void deleteDeadBlocksFromLoop(Loop &L,
MemorySSAUpdater *MSSAU) {
// Find all the dead blocks tied to this loop, and remove them from their
// successors.
- SmallPtrSet DeadBlockSet;
+ SmallSetVector DeadBlockSet;
// Start with loop/exit blocks and get a transitive closure of reachable dead
// blocks.
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index 91d33cb0f20ea..39b6b889f91c4 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -2238,7 +2238,7 @@ bool llvm::removeUnreachableBlocks(Function &F, LazyValueInfo *LVI,
assert(Reachable.size() < F.size());
NumRemoved += F.size()-Reachable.size();
- SmallPtrSet DeadBlockSet;
+ SmallSetVector DeadBlockSet;
for (Function::iterator I = ++F.begin(), E = F.end(); I != E; ++I) {
auto *BB = &*I;
if (Reachable.count(BB))
diff --git a/llvm/lib/Transforms/Utils/LoopSimplify.cpp b/llvm/lib/Transforms/Utils/LoopSimplify.cpp
index 5ec12aafff05b..7e6da02d57077 100644
--- a/llvm/lib/Transforms/Utils/LoopSimplify.cpp
+++ b/llvm/lib/Transforms/Utils/LoopSimplify.cpp
@@ -681,7 +681,8 @@ static bool simplifyOneLoop(Loop *L, SmallVectorImpl &Worklist,
}
DT->eraseNode(ExitingBlock);
if (MSSAU) {
- SmallPtrSet ExitBlockSet{ExitingBlock};
+ SmallSetVector ExitBlockSet;
+ ExitBlockSet.insert(ExitingBlock);
MSSAU->removeBlocks(ExitBlockSet);
}
diff --git a/llvm/test/Analysis/MemorySSA/nondeterminism.ll b/llvm/test/Analysis/MemorySSA/nondeterminism.ll
new file mode 100644
index 0000000000000..0bb3df30b5878
--- /dev/null
+++ b/llvm/test/Analysis/MemorySSA/nondeterminism.ll
@@ -0,0 +1,122 @@
+; RUN: opt -simplifycfg -enable-mssa-loop-dependency -S --preserve-ll-uselistorder %s | FileCheck %s
+; REQUIRES: x86-registered-target
+; CHECK-LABEL: @n
+; CHECK: uselistorder i16 0, { 3, 2, 4, 1, 5, 0, 6 }
+
+; Note: test was added in an effort to ensure determinism when updating memoryssa. See PR42574.
+; If the uselistorder check becomes no longer relevant, the test can be disabled or removed.
+
+%rec9 = type { i16, i32, i32 }
+
+@a = global [1 x [1 x %rec9]] zeroinitializer
+
+define i16 @n() {
+ br label %..split_crit_edge
+
+..split_crit_edge: ; preds = %0
+ br label %.split
+
+bb4.us4: ; preds = %bb2.split.us32, %bb6.us28
+ %i.4.01.us5 = phi i16 [ %_tmp49.us30, %bb6.us28 ]
+ br label %g.exit4.us21
+
+bb1.i.us14: ; preds = %bb4.us4
+ br label %g.exit4.us21
+
+g.exit4.us21: ; preds = %bb1.i.us14, %g.exit4.critedge.us9
+ %i.4.02.us22 = phi i16 [ %i.4.01.us5, %bb4.us4 ], [ %i.4.01.us5, %bb1.i.us14 ]
+ br label %bb6.us28
+
+bb5.us26: ; preds = %g.exit4.us21
+ br label %bb6.us28
+
+bb6.us28: ; preds = %bb5.us26, %g.exit4.us21
+ %i.4.03.us29 = phi i16 [ %i.4.02.us22, %bb5.us26 ], [ %i.4.02.us22, %g.exit4.us21 ]
+ %_tmp49.us30 = add nuw nsw i16 %i.4.03.us29, 1
+ br label %bb4.us4
+
+bb4.us.us: ; preds = %bb2.split.us.us, %bb6.us.us
+ %i.4.01.us.us = phi i16 [ %_tmp49.us.us, %bb6.us.us ]
+ br label %bb1.i.us.us
+
+bb1.i.us.us: ; preds = %bb4.us.us
+ br label %g.exit4.us.us
+
+g.exit4.us.us: ; preds = %bb1.i.us.us, %g.exit4.critedge.us.us
+ %i.4.02.us.us = phi i16 [ %i.4.01.us.us, %bb1.i.us.us ]
+ br label %bb5.us.us
+
+bb5.us.us: ; preds = %g.exit4.us.us
+ br label %bb6.us.us
+
+bb6.us.us: ; preds = %bb5.us.us, %g.exit4.us.us
+ %i.4.03.us.us = phi i16 [ %i.4.02.us.us, %bb5.us.us ]
+ %_tmp49.us.us = add nuw nsw i16 %i.4.03.us.us, 1
+ br label %bb4.us.us
+
+
+.split: ; preds = %..split_crit_edge
+ br label %bb2
+
+bb2: ; preds = %.split, %bb7
+ %h.3.0 = phi i16 [ undef, %.split ], [ %_tmp53, %bb7 ]
+ br label %bb2.bb2.split_crit_edge
+
+bb2.bb2.split_crit_edge: ; preds = %bb2
+ br label %bb2.split
+
+bb2.split.us: ; preds = %bb2
+ br label %bb4.us
+
+bb4.us: ; preds = %bb6.us, %bb2.split.us
+ %i.4.01.us = phi i16 [ 0, %bb2.split.us ]
+ br label %bb1.i.us
+
+g.exit4.critedge.us: ; preds = %bb4.us
+ br label %g.exit4.us
+
+bb1.i.us: ; preds = %bb4.us
+ br label %g.exit4.us
+
+g.exit4.us: ; preds = %bb1.i.us, %g.exit4.critedge.us
+ %i.4.02.us = phi i16 [ %i.4.01.us, %g.exit4.critedge.us ], [ %i.4.01.us, %bb1.i.us ]
+ br label %bb5.us
+
+bb5.us: ; preds = %g.exit4.us
+ br label %bb7
+
+bb2.split: ; preds = %bb2.bb2.split_crit_edge
+ br label %bb4
+
+bb4: ; preds = %bb2.split, %bb6
+ %i.4.01 = phi i16 [ 0, %bb2.split ]
+ %_tmp16 = getelementptr [1 x [1 x %rec9]], [1 x [1 x %rec9]]* @a, i16 0, i16 %h.3.0, i16 %i.4.01, i32 0
+ %_tmp17 = load i16, i16* %_tmp16, align 1
+ br label %g.exit4.critedge
+
+bb1.i: ; preds = %bb4
+ br label %g.exit4
+
+g.exit4.critedge: ; preds = %bb4
+ %_tmp28.c = getelementptr [1 x [1 x %rec9]], [1 x [1 x %rec9]]* @a, i16 0, i16 %h.3.0, i16 %i.4.01, i32 1
+ %_tmp29.c = load i32, i32* %_tmp28.c, align 1
+ %_tmp30.c = trunc i32 %_tmp29.c to i16
+ br label %g.exit4
+
+g.exit4: ; preds = %g.exit4.critedge, %bb1.i
+ %i.4.02 = phi i16 [ %i.4.01, %g.exit4.critedge ], [ %i.4.01, %bb1.i ]
+ %_tmp41 = getelementptr [1 x [1 x %rec9]], [1 x [1 x %rec9]]* @a, i16 0, i16 %h.3.0, i16 %i.4.02, i32 2
+ br label %bb6
+
+bb5: ; preds = %g.exit4
+ br label %bb6
+
+bb6: ; preds = %bb5, %g.exit4
+ %i.4.03 = phi i16 [ %i.4.02, %bb5 ], [ %i.4.02, %g.exit4 ]
+ %_tmp49 = add nuw nsw i16 %i.4.03, 1
+ br label %bb7
+
+bb7: ; preds = %bb7.us-lcssa.us, %bb7.us-lcssa
+ %_tmp53 = add nsw i16 %h.3.0, 1
+ br label %bb2
+}
From b1bff76e22bd39eb46dcae49891fda1cf1cc0bd5 Mon Sep 17 00:00:00 2001
From: Vitaly Buka
Date: Fri, 12 Jul 2019 22:37:55 +0000
Subject: [PATCH 008/451] isBytewiseValue checks ConstantVector element by
element
Summary: Vector of the same value with few undefs will sill be considered "Bytewise"
Reviewers: eugenis, pcc, jfb
Reviewed By: jfb
Subscribers: dexonsmith, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D64031
llvm-svn: 365971
---
llvm/lib/Analysis/ValueTracking.cpp | 7 +------
llvm/unittests/Analysis/ValueTrackingTest.cpp | 2 +-
2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index cf8fa9cee3fc8..ad8034b2d7bc5 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3253,12 +3253,7 @@ Value *llvm::isBytewiseValue(Value *V, const DataLayout &DL) {
return Val;
}
- if (isa(C)) {
- Constant *Splat = cast(C)->getSplatValue();
- return Splat ? isBytewiseValue(Splat, DL) : nullptr;
- }
-
- if (isa(C) || isa(C)) {
+ if (isa(C)) {
Value *Val = UndefInt8;
for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I)
if (!(Val = Merge(Val, isBytewiseValue(C->getOperand(I), DL))))
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index f4316cc8575c4..96b41d93d568a 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -878,7 +878,7 @@ const std::pair IsBytewiseValueTests[] = {
"<4 x i8> ",
},
{
- "",
+ "i8 5",
"<2 x i8> < i8 5, i8 undef >",
},
{
From 1dfae6fe505ffedf97e9f36d207cb8bbdc9255d8 Mon Sep 17 00:00:00 2001
From: Stanislav Mekhanoshin
Date: Fri, 12 Jul 2019 22:42:01 +0000
Subject: [PATCH 009/451] [AMDGPU] use v32f32 for 3 mfma intrinsics
These should really use v32f32, but were defined as v32i32
due to the lack of the v32f32 type.
Differential Revision: https://reviews.llvm.org/D64667
llvm-svn: 365972
---
llvm/include/llvm/IR/Intrinsics.td | 1 +
llvm/include/llvm/IR/IntrinsicsAMDGPU.td | 12 ++--
llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp | 9 +++
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 6 +-
llvm/lib/Target/AMDGPU/SIInstrInfo.td | 7 +-
llvm/lib/Target/AMDGPU/SIInstructions.td | 12 ++++
llvm/lib/Target/AMDGPU/SIRegisterInfo.td | 8 +--
.../CodeGen/AMDGPU/agpr-register-count.ll | 8 +--
llvm/test/CodeGen/AMDGPU/llvm.amdgcn.mfma.ll | 64 +++++++++----------
llvm/test/CodeGen/AMDGPU/spill-agpr.ll | 10 +--
.../test/CodeGen/AMDGPU/spill-vgpr-to-agpr.ll | 10 ++-
11 files changed, 87 insertions(+), 60 deletions(-)
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 62e94108a7355..8276d7535c3b2 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -261,6 +261,7 @@ def llvm_v2f32_ty : LLVMType; // 2 x float
def llvm_v4f32_ty : LLVMType; // 4 x float
def llvm_v8f32_ty : LLVMType; // 8 x float
def llvm_v16f32_ty : LLVMType; // 16 x float
+def llvm_v32f32_ty : LLVMType; // 32 x float
def llvm_v1f64_ty : LLVMType; // 1 x double
def llvm_v2f64_ty : LLVMType; // 2 x double
def llvm_v4f64_ty : LLVMType; // 4 x double
diff --git a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td
index 56878e1240749..43e827ec6ab99 100644
--- a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td
+++ b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td
@@ -1663,8 +1663,8 @@ def int_amdgcn_buffer_atomic_fadd : AMDGPUBufferAtomicNoRtn;
def int_amdgcn_global_atomic_fadd : AMDGPUGlobalAtomicNoRtn;
// llvm.amdgcn.mfma.f32.* vdst, srcA, srcB, srcC, cbsz, abid, blgp
-def int_amdgcn_mfma_f32_32x32x1f32 : Intrinsic<[llvm_v32i32_ty],
- [llvm_float_ty, llvm_float_ty, llvm_v32i32_ty,
+def int_amdgcn_mfma_f32_32x32x1f32 : Intrinsic<[llvm_v32f32_ty],
+ [llvm_float_ty, llvm_float_ty, llvm_v32f32_ty,
llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrConvergent, IntrNoMem]>;
def int_amdgcn_mfma_f32_16x16x1f32 : Intrinsic<[llvm_v16f32_ty],
@@ -1683,8 +1683,8 @@ def int_amdgcn_mfma_f32_16x16x4f32 : Intrinsic<[llvm_v4f32_ty],
[llvm_float_ty, llvm_float_ty, llvm_v4f32_ty,
llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrConvergent, IntrNoMem]>;
-def int_amdgcn_mfma_f32_32x32x4f16 : Intrinsic<[llvm_v32i32_ty],
- [llvm_v4f16_ty, llvm_v4f16_ty, llvm_v32i32_ty,
+def int_amdgcn_mfma_f32_32x32x4f16 : Intrinsic<[llvm_v32f32_ty],
+ [llvm_v4f16_ty, llvm_v4f16_ty, llvm_v32f32_ty,
llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrConvergent, IntrNoMem]>;
def int_amdgcn_mfma_f32_16x16x4f16 : Intrinsic<[llvm_v16f32_ty],
@@ -1723,8 +1723,8 @@ def int_amdgcn_mfma_i32_16x16x16i8 : Intrinsic<[llvm_v4i32_ty],
[llvm_i32_ty, llvm_i32_ty, llvm_v4i32_ty,
llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrConvergent, IntrNoMem]>;
-def int_amdgcn_mfma_f32_32x32x2bf16 : Intrinsic<[llvm_v32i32_ty],
- [llvm_v2i16_ty, llvm_v2i16_ty, llvm_v32i32_ty,
+def int_amdgcn_mfma_f32_32x32x2bf16 : Intrinsic<[llvm_v32f32_ty],
+ [llvm_v2i16_ty, llvm_v2i16_ty, llvm_v32f32_ty,
llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrConvergent, IntrNoMem]>;
def int_amdgcn_mfma_f32_16x16x2bf16 : Intrinsic<[llvm_v16f32_ty],
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index 56922b0505064..14ae62968c65b 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -165,6 +165,9 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::LOAD, MVT::v16f32, Promote);
AddPromotedToType(ISD::LOAD, MVT::v16f32, MVT::v16i32);
+ setOperationAction(ISD::LOAD, MVT::v32f32, Promote);
+ AddPromotedToType(ISD::LOAD, MVT::v32f32, MVT::v32i32);
+
setOperationAction(ISD::LOAD, MVT::i64, Promote);
AddPromotedToType(ISD::LOAD, MVT::i64, MVT::v2i32);
@@ -256,6 +259,9 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::STORE, MVT::v16f32, Promote);
AddPromotedToType(ISD::STORE, MVT::v16f32, MVT::v16i32);
+ setOperationAction(ISD::STORE, MVT::v32f32, Promote);
+ AddPromotedToType(ISD::STORE, MVT::v32f32, MVT::v32i32);
+
setOperationAction(ISD::STORE, MVT::i64, Promote);
AddPromotedToType(ISD::STORE, MVT::i64, MVT::v2i32);
@@ -355,7 +361,10 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v5i32, Custom);
setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v8f32, Custom);
setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v8i32, Custom);
+ setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v16f32, Custom);
setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v16i32, Custom);
+ setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v32f32, Custom);
+ setOperationAction(ISD::EXTRACT_SUBVECTOR, MVT::v32i32, Custom);
setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand);
setOperationAction(ISD::FP_TO_FP16, MVT::f64, Custom);
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 3eb1b1c91066c..b90a0d28e9ef0 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -153,6 +153,7 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
if (Subtarget->hasMAIInsts()) {
addRegisterClass(MVT::v32i32, &AMDGPU::AReg_1024RegClass);
+ addRegisterClass(MVT::v32f32, &AMDGPU::AReg_1024RegClass);
}
computeRegisterProperties(Subtarget->getRegisterInfo());
@@ -263,8 +264,9 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
// We only support LOAD/STORE and vector manipulation ops for vectors
// with > 4 elements.
- for (MVT VT : {MVT::v8i32, MVT::v8f32, MVT::v16i32, MVT::v16f32,
- MVT::v2i64, MVT::v2f64, MVT::v4i16, MVT::v4f16, MVT::v32i32 }) {
+ for (MVT VT : { MVT::v8i32, MVT::v8f32, MVT::v16i32, MVT::v16f32,
+ MVT::v2i64, MVT::v2f64, MVT::v4i16, MVT::v4f16,
+ MVT::v32i32, MVT::v32f32 }) {
for (unsigned Op = 0; Op < ISD::BUILTIN_OP_END; ++Op) {
switch (Op) {
case ISD::LOAD:
diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
index 98928f00a4568..c382c816e0b40 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
@@ -2178,14 +2178,13 @@ def VOP_I32_V2I16_V2I16_I32 : VOPProfile <[i32, v2i16, v2i16, i32]>;
def VOP_V4F32_F32_F32_V4F32 : VOPProfile <[v4f32, f32, f32, v4f32]>;
def VOP_V16F32_F32_F32_V16F32 : VOPProfile <[v16f32, f32, f32, v16f32]>;
-// TODO: define v32f32
-def VOP_V32F32_F32_F32_V32F32 : VOPProfile <[v32i32, f32, f32, v32i32]>;
+def VOP_V32F32_F32_F32_V32F32 : VOPProfile <[v32f32, f32, f32, v32f32]>;
def VOP_V4F32_V4F16_V4F16_V4F32 : VOPProfile <[v4f32, v4f16, v4f16, v4f32]>;
def VOP_V16F32_V4F16_V4F16_V16F32 : VOPProfile <[v16f32, v4f16, v4f16, v16f32]>;
-def VOP_V32F32_V4F16_V4F16_V32F32 : VOPProfile <[v32i32, v4f16, v4f16, v32i32]>;
+def VOP_V32F32_V4F16_V4F16_V32F32 : VOPProfile <[v32f32, v4f16, v4f16, v32f32]>;
def VOP_V4F32_V2I16_V2I16_V4F32 : VOPProfile <[v4f32, v2i16, v2i16, v4f32]>;
def VOP_V16F32_V2I16_V2I16_V16F32 : VOPProfile <[v16f32, v2i16, v2i16, v16f32]>;
-def VOP_V32F32_V2I16_V2I16_V32F32 : VOPProfile <[v32i32, v2i16, v2i16, v32i32]>;
+def VOP_V32F32_V2I16_V2I16_V32F32 : VOPProfile <[v32f32, v2i16, v2i16, v32f32]>;
def VOP_V4I32_I32_I32_V4I32 : VOPProfile <[v4i32, i32, i32, v4i32]>;
def VOP_V16I32_I32_I32_V16I32 : VOPProfile <[v16i32, i32, i32, v16i32]>;
def VOP_V32I32_I32_I32_V32I32 : VOPProfile <[v32i32, i32, i32, v32i32]>;
diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td
index fd4b6f5e3e31d..70f20bb693704 100644
--- a/llvm/lib/Target/AMDGPU/SIInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SIInstructions.td
@@ -942,6 +942,14 @@ foreach Index = 0-31 in {
def Insert_Element_v32i32_#Index : Insert_Element <
i32, v32i32, Index, !cast(sub#Index)
>;
+
+ def Extract_Element_v32f32_#Index : Extract_Element <
+ f32, v32f32, Index, !cast(sub#Index)
+ >;
+
+ def Insert_Element_v32f32_#Index : Insert_Element <
+ f32, v32f32, Index, !cast(sub#Index)
+ >;
}
// FIXME: Why do only some of these type combinations for SReg and
@@ -1034,6 +1042,10 @@ def : BitConvert ;
def : BitConvert ;
def : BitConvert ;
+// 1024-bit bitcast
+def : BitConvert ;
+def : BitConvert ;
+
/********** =================== **********/
/********** Src & Dst modifiers **********/
/********** =================== **********/
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
index 14d41d84cbadc..4767f3c30ed32 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
@@ -757,11 +757,11 @@ def VRegOrLds_32 : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 3
let isAllocatable = 0;
}
-def SGPR_1024 : RegisterClass<"AMDGPU", [v32i32], 32, (add SGPR_1024Regs)> {
+def SGPR_1024 : RegisterClass<"AMDGPU", [v32i32, v32f32], 32, (add SGPR_1024Regs)> {
let AllocationPriority = 19;
}
-def SReg_1024 : RegisterClass<"AMDGPU", [v32i32], 32,
+def SReg_1024 : RegisterClass<"AMDGPU", [v32i32, v32f32], 32,
(add SGPR_1024)> {
let CopyCost = 16;
let AllocationPriority = 19;
@@ -812,7 +812,7 @@ def VReg_512 : RegisterClass<"AMDGPU", [v16i32, v16f32], 32, (add VGPR_512)> {
let AllocationPriority = 7;
}
-def VReg_1024 : RegisterClass<"AMDGPU", [v32i32], 32, (add VGPR_1024)> {
+def VReg_1024 : RegisterClass<"AMDGPU", [v32i32, v32f32], 32, (add VGPR_1024)> {
let Size = 1024;
let CopyCost = 32;
let AllocationPriority = 8;
@@ -840,7 +840,7 @@ def AReg_512 : RegisterClass<"AMDGPU", [v16i32, v16f32], 32, (add AGPR_512)> {
}
// TODO: add v32f32 value type
-def AReg_1024 : RegisterClass<"AMDGPU", [v32i32], 32, (add AGPR_1024)> {
+def AReg_1024 : RegisterClass<"AMDGPU", [v32i32, v32f32], 32, (add AGPR_1024)> {
let Size = 1024;
let CopyCost = 65;
let AllocationPriority = 8;
diff --git a/llvm/test/CodeGen/AMDGPU/agpr-register-count.ll b/llvm/test/CodeGen/AMDGPU/agpr-register-count.ll
index ab4fcc54f65c8..dfedd2402a03f 100644
--- a/llvm/test/CodeGen/AMDGPU/agpr-register-count.ll
+++ b/llvm/test/CodeGen/AMDGPU/agpr-register-count.ll
@@ -1,15 +1,15 @@
; RUN: llc -march=amdgcn -mcpu=gfx908 -verify-machineinstrs < %s | FileCheck -check-prefix=GCN %s
-declare <32 x i32> @llvm.amdgcn.mfma.f32.32x32x1f32(float, float, <32 x i32>, i32, i32, i32)
+declare <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float, float, <32 x float>, i32, i32, i32)
; GCN-LABEL: {{^}}test_32_agprs:
; GCN: v_mfma_f32_32x32x1f32 a[0:31], {{v[0-9]+}}, {{v[0-9]+}}, 0
; GCN-NOT: v28
; GCN: NumVgprs: 32
; GCN: VGPRBlocks: 7
-define amdgpu_kernel void @test_32_agprs(<32 x i32> addrspace(1)* %arg) {
+define amdgpu_kernel void @test_32_agprs(<32 x float> addrspace(1)* %arg) {
bb:
- %mai.1 = tail call <32 x i32> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x i32> , i32 0, i32 0, i32 0)
- store <32 x i32> %mai.1, <32 x i32> addrspace(1)* %arg
+ %mai.1 = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x float> , i32 0, i32 0, i32 0)
+ store <32 x float> %mai.1, <32 x float> addrspace(1)* %arg
ret void
}
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.mfma.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.mfma.ll
index 0ce08777c14b5..5ac03632fbbe0 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.mfma.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.mfma.ll
@@ -1,11 +1,11 @@
; RUN: llc -march=amdgcn -mcpu=gfx908 -verify-machineinstrs < %s | FileCheck -check-prefix=GCN %s
-declare <32 x i32> @llvm.amdgcn.mfma.f32.32x32x1f32(float, float, <32 x i32>, i32, i32, i32)
+declare <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float, float, <32 x float>, i32, i32, i32)
declare <16 x float> @llvm.amdgcn.mfma.f32.16x16x1f32(float, float, <16 x float>, i32, i32, i32)
declare <4 x float> @llvm.amdgcn.mfma.f32.4x4x1f32(float, float, <4 x float>, i32, i32, i32)
declare <16 x float> @llvm.amdgcn.mfma.f32.32x32x2f32(float, float, <16 x float>, i32, i32, i32)
declare <4 x float> @llvm.amdgcn.mfma.f32.16x16x4f32(float, float, <4 x float>, i32, i32, i32)
-declare <32 x i32> @llvm.amdgcn.mfma.f32.32x32x4f16(<4 x half>, <4 x half>, <32 x i32>, i32, i32, i32)
+declare <32 x float> @llvm.amdgcn.mfma.f32.32x32x4f16(<4 x half>, <4 x half>, <32 x float>, i32, i32, i32)
declare <16 x float> @llvm.amdgcn.mfma.f32.16x16x4f16(<4 x half>, <4 x half>, <16 x float>, i32, i32, i32)
declare <4 x float> @llvm.amdgcn.mfma.f32.4x4x4f16(<4 x half>, <4 x half>, <4 x float>, i32, i32, i32)
declare <16 x float> @llvm.amdgcn.mfma.f32.32x32x8f16(<4 x half>, <4 x half>, <16 x float>, i32, i32, i32)
@@ -15,7 +15,7 @@ declare <16 x i32> @llvm.amdgcn.mfma.i32.16x16x4i8(i32, i32, <16 x i32>, i32, i3
declare <4 x i32> @llvm.amdgcn.mfma.i32.4x4x4i8(i32, i32, <4 x i32>, i32, i32, i32)
declare <16 x i32> @llvm.amdgcn.mfma.i32.32x32x8i8(i32, i32, <16 x i32>, i32, i32, i32)
declare <4 x i32> @llvm.amdgcn.mfma.i32.16x16x16i8(i32, i32, <4 x i32>, i32, i32, i32)
-declare <32 x i32> @llvm.amdgcn.mfma.f32.32x32x2bf16(<2 x i16>, <2 x i16>, <32 x i32>, i32, i32, i32)
+declare <32 x float> @llvm.amdgcn.mfma.f32.32x32x2bf16(<2 x i16>, <2 x i16>, <32 x float>, i32, i32, i32)
declare <16 x float> @llvm.amdgcn.mfma.f32.16x16x2bf16(<2 x i16>, <2 x i16>, <16 x float>, i32, i32, i32)
declare <4 x float> @llvm.amdgcn.mfma.f32.4x4x2bf16(<2 x i16>, <2 x i16>, <4 x float>, i32, i32, i32)
declare <16 x float> @llvm.amdgcn.mfma.f32.32x32x4bf16(<2 x i16>, <2 x i16>, <16 x float>, i32, i32, i32)
@@ -100,11 +100,11 @@ declare i32 @llvm.amdgcn.workitem.id.x()
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
-define amdgpu_kernel void @test_mfma_f32_32x32x1f32(<32 x i32> addrspace(1)* %arg) {
+define amdgpu_kernel void @test_mfma_f32_32x32x1f32(<32 x float> addrspace(1)* %arg) {
bb:
- %in.1 = load <32 x i32>, <32 x i32> addrspace(1)* %arg
- %mai.1 = tail call <32 x i32> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x i32> %in.1, i32 1, i32 2, i32 3)
- store <32 x i32> %mai.1, <32 x i32> addrspace(1)* %arg
+ %in.1 = load <32 x float>, <32 x float> addrspace(1)* %arg
+ %mai.1 = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x float> %in.1, i32 1, i32 2, i32 3)
+ store <32 x float> %mai.1, <32 x float> addrspace(1)* %arg
ret void
}
@@ -326,14 +326,14 @@ bb:
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
-define amdgpu_kernel void @test_mfma_f32_32x32x4f16(<32 x i32> addrspace(1)* %arg, <4 x half> addrspace(1)* %c) {
+define amdgpu_kernel void @test_mfma_f32_32x32x4f16(<32 x float> addrspace(1)* %arg, <4 x half> addrspace(1)* %c) {
bb:
- %in.1 = load <32 x i32>, <32 x i32> addrspace(1)* %arg
+ %in.1 = load <32 x float>, <32 x float> addrspace(1)* %arg
%c.1 = load <4 x half>, <4 x half> addrspace(1)* %c
%c2p = getelementptr <4 x half>, <4 x half> addrspace(1)* %c, i64 1
%c.2 = load <4 x half>, <4 x half> addrspace(1)* %c2p
- %mai.1 = tail call <32 x i32> @llvm.amdgcn.mfma.f32.32x32x4f16(<4 x half> %c.1, <4 x half> %c.2, <32 x i32> %in.1, i32 1, i32 2, i32 3)
- store <32 x i32> %mai.1, <32 x i32> addrspace(1)* %arg
+ %mai.1 = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x4f16(<4 x half> %c.1, <4 x half> %c.2, <32 x float> %in.1, i32 1, i32 2, i32 3)
+ store <32 x float> %mai.1, <32 x float> addrspace(1)* %arg
ret void
}
@@ -794,13 +794,13 @@ bb:
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
-define amdgpu_kernel void @test_mfma_f32_32x32x2bf16(<32 x i32> addrspace(1)* %arg) {
+define amdgpu_kernel void @test_mfma_f32_32x32x2bf16(<32 x float> addrspace(1)* %arg) {
bb:
- %in.1 = load <32 x i32>, <32 x i32> addrspace(1)* %arg
+ %in.1 = load <32 x float>, <32 x float> addrspace(1)* %arg
%a = bitcast i32 1 to <2 x i16>
%b = bitcast i32 2 to <2 x i16>
- %mai.1 = tail call <32 x i32> @llvm.amdgcn.mfma.f32.32x32x2bf16(<2 x i16> %a, <2 x i16> %b, <32 x i32> %in.1, i32 1, i32 2, i32 3)
- store <32 x i32> %mai.1, <32 x i32> addrspace(1)* %arg
+ %mai.1 = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x2bf16(<2 x i16> %a, <2 x i16> %b, <32 x float> %in.1, i32 1, i32 2, i32 3)
+ store <32 x float> %mai.1, <32 x float> addrspace(1)* %arg
ret void
}
@@ -957,12 +957,12 @@ bb:
; GCN-LABEL: {{^}}test_mfma_f32_32x32x1f32_forward_acc:
; GCN: v_mfma_f32_32x32x1f32 [[MAI1:a\[[0-9]+:[0-9]+\]]], v{{[0-9]+}}, v{{[0-9]+}}, a[{{[0-9]+:[0-9]+}}]
; GCN-NEXT: v_mfma_f32_32x32x1f32 a[{{[0-9]+:[0-9]+}}], v{{[0-9]+}}, v{{[0-9]+}}, [[MAI1]]
-define amdgpu_kernel void @test_mfma_f32_32x32x1f32_forward_acc(<32 x i32> addrspace(1)* %arg) {
+define amdgpu_kernel void @test_mfma_f32_32x32x1f32_forward_acc(<32 x float> addrspace(1)* %arg) {
bb:
- %in.1 = load <32 x i32>, <32 x i32> addrspace(1)* %arg
- %mai.1 = tail call <32 x i32> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x i32> %in.1, i32 0, i32 0, i32 0)
- %mai.2 = tail call <32 x i32> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x i32> %mai.1, i32 0, i32 0, i32 0)
- store <32 x i32> %mai.2, <32 x i32> addrspace(1)* %arg
+ %in.1 = load <32 x float>, <32 x float> addrspace(1)* %arg
+ %mai.1 = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x float> %in.1, i32 0, i32 0, i32 0)
+ %mai.2 = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x float> %mai.1, i32 0, i32 0, i32 0)
+ store <32 x float> %mai.2, <32 x float> addrspace(1)* %arg
ret void
}
@@ -1112,10 +1112,10 @@ bb:
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
-define amdgpu_kernel void @test_mfma_f32_32x32x1f32_imm_splat(<32 x i32> addrspace(1)* %arg) {
+define amdgpu_kernel void @test_mfma_f32_32x32x1f32_imm_splat(<32 x float> addrspace(1)* %arg) {
bb:
- %mai.1 = tail call <32 x i32> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x i32> , i32 0, i32 0, i32 0)
- store <32 x i32> %mai.1, <32 x i32> addrspace(1)* %arg
+ %mai.1 = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x float> , i32 0, i32 0, i32 0)
+ store <32 x float> %mai.1, <32 x float> addrspace(1)* %arg
ret void
}
@@ -1184,7 +1184,7 @@ bb:
; GCN-LABEL: {{^}}test_mfma_f32_32x32x1f32_imm:
; GCN-DAG: v_accvgpr_write_b32 a{{[0-9]+}}, 0
-; GCN-DAG: v_accvgpr_write_b32 a{{[0-9]+}}, 1
+; GCN-DAG: v_accvgpr_write_b32 a{{[0-9]+}}, 1.0
; GCN-DAG: v_accvgpr_write_b32 a{{[0-9]+}}, 0
; GCN-DAG: v_accvgpr_write_b32 a{{[0-9]+}}, 0
; GCN-DAG: v_accvgpr_write_b32 a{{[0-9]+}}, 0
@@ -1256,10 +1256,10 @@ bb:
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
-define amdgpu_kernel void @test_mfma_f32_32x32x1f32_imm(<32 x i32> addrspace(1)* %arg) {
+define amdgpu_kernel void @test_mfma_f32_32x32x1f32_imm(<32 x float> addrspace(1)* %arg) {
bb:
- %mai.1 = tail call <32 x i32> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x i32> , i32 0, i32 0, i32 0)
- store <32 x i32> %mai.1, <32 x i32> addrspace(1)* %arg
+ %mai.1 = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x float> , i32 0, i32 0, i32 0)
+ store <32 x float> %mai.1, <32 x float> addrspace(1)* %arg
ret void
}
@@ -1350,12 +1350,12 @@ bb:
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
; GCN-DAG: global_store_dwordx4
-define amdgpu_kernel void @test_mfma_f32_32x32x1f32_vecarg(<32 x i32> addrspace(1)* %arg) {
+define amdgpu_kernel void @test_mfma_f32_32x32x1f32_vecarg(<32 x float> addrspace(1)* %arg) {
bb:
%tid = call i32 @llvm.amdgcn.workitem.id.x()
- %gep = getelementptr inbounds <32 x i32>, <32 x i32> addrspace(1)* %arg, i32 %tid
- %in.1 = load <32 x i32>, <32 x i32> addrspace(1)* %gep
- %mai.1 = tail call <32 x i32> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x i32> %in.1, i32 1, i32 2, i32 3)
- store <32 x i32> %mai.1, <32 x i32> addrspace(1)* %gep
+ %gep = getelementptr inbounds <32 x float>, <32 x float> addrspace(1)* %arg, i32 %tid
+ %in.1 = load <32 x float>, <32 x float> addrspace(1)* %gep
+ %mai.1 = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 2.0, <32 x float> %in.1, i32 1, i32 2, i32 3)
+ store <32 x float> %mai.1, <32 x float> addrspace(1)* %gep
ret void
}
diff --git a/llvm/test/CodeGen/AMDGPU/spill-agpr.ll b/llvm/test/CodeGen/AMDGPU/spill-agpr.ll
index b12a7bc72a819..9c7279a78e75e 100644
--- a/llvm/test/CodeGen/AMDGPU/spill-agpr.ll
+++ b/llvm/test/CodeGen/AMDGPU/spill-agpr.ll
@@ -84,23 +84,23 @@ define amdgpu_kernel void @max_10_vgprs_used_9a(i32 addrspace(1)* %p) #1 {
; A2M: buffer_load_dword v[[VSPILL:[0-9]+]], off, s[{{[0-9:]+}}], s{{[0-9]+}} offset:[[FI]] ; 4-byte Folded Reload
; GFX908: v_accvgpr_write_b32 a{{[0-9]+}}, v[[VSPILL]]
; A2V: ScratchSize: 0
-define amdgpu_kernel void @max_32regs_mfma32(i32 addrspace(1)* %arg) #3 {
+define amdgpu_kernel void @max_32regs_mfma32(float addrspace(1)* %arg) #3 {
bb:
%v = call i32 asm sideeffect "", "=a"()
br label %use
use:
- %mai.1 = tail call <32 x i32> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 1.0, <32 x i32> , i32 0, i32 0, i32 0)
+ %mai.1 = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.0, float 1.0, <32 x float> , i32 0, i32 0, i32 0)
call void asm sideeffect "", "a"(i32 %v)
- %elt1 = extractelement <32 x i32> %mai.1, i32 0
- store i32 %elt1, i32 addrspace(1)* %arg
+ %elt1 = extractelement <32 x float> %mai.1, i32 0
+ store float %elt1, float addrspace(1)* %arg
ret void
}
declare i32 @llvm.amdgcn.workitem.id.x()
declare <16 x float> @llvm.amdgcn.mfma.f32.16x16x1f32(float, float, <16 x float>, i32, i32, i32)
declare <4 x float> @llvm.amdgcn.mfma.f32.4x4x1f32(float, float, <4 x float>, i32, i32, i32)
-declare <32 x i32> @llvm.amdgcn.mfma.f32.32x32x1f32(float, float, <32 x i32>, i32, i32, i32)
+declare <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float, float, <32 x float>, i32, i32, i32)
attributes #0 = { nounwind "amdgpu-num-vgpr"="24" }
attributes #1 = { nounwind "amdgpu-num-vgpr"="8" }
diff --git a/llvm/test/CodeGen/AMDGPU/spill-vgpr-to-agpr.ll b/llvm/test/CodeGen/AMDGPU/spill-vgpr-to-agpr.ll
index b101e41833b8e..6eef782d1906d 100644
--- a/llvm/test/CodeGen/AMDGPU/spill-vgpr-to-agpr.ll
+++ b/llvm/test/CodeGen/AMDGPU/spill-vgpr-to-agpr.ll
@@ -233,19 +233,23 @@ define amdgpu_kernel void @max_256_vgprs_spill_9x32(<32 x float> addrspace(1)* %
ret void
}
+; FIXME: adding an AReg_1024 register class for v32f32 and v32i32
+; produces unnecessary copies and we still have some amount
+; of conventional spilling.
+
; GCN-LABEL: {{^}}max_256_vgprs_spill_9x32_2bb:
; GFX900-DAG: s_mov_b32 s{{[0-9]+}}, SCRATCH_RSRC_DWORD0
; GFX900-DAG: s_mov_b32 s{{[0-9]+}}, SCRATCH_RSRC_DWORD1
-; GFX908-NOT: SCRATCH_RSRC
+; GFX908-FIXME-NOT: SCRATCH_RSRC
; GFX908-DAG: v_accvgpr_write_b32 a0, v
; GFX900: buffer_store_dword v
; GFX900: buffer_load_dword v
-; GFX908-NOT: buffer_
+; GFX908-FIXME-NOT: buffer_
; GFX908-DAG v_accvgpr_read_b32
; GCN: NumVgprs: 256
; GFX900: ScratchSize: 580
-; GFX908: ScratchSize: 0
+; GFX908-FIXME: ScratchSize: 0
; GCN: VGPRBlocks: 63
; GCN: NumVGPRsForWavesPerEU: 256
define amdgpu_kernel void @max_256_vgprs_spill_9x32_2bb(<32 x float> addrspace(1)* %p) {
From 882fdf68b74d3199cb84b062709b702ed610f547 Mon Sep 17 00:00:00 2001
From: Eric Fiselier
Date: Fri, 12 Jul 2019 23:01:48 +0000
Subject: [PATCH 010/451] Fix non-conformance it `std::tuple`.
Previously we implemented all one trillion tuple-like constructors using
a single generic overload. This worked fairly well, except that it
differed in behavior from the standard version because it didn't
consider both T&& and T const&. This was observable for certain
types.
This patch addresses that issue by splitting the generic constructor
in two. We now provide both T&& and T const& versions of the
tuple-like constructors (sort of).
llvm-svn: 365973
---
libcxx/include/tuple | 51 +++++++++++--------
.../tuple.cnstr/convert_copy.pass.cpp | 16 ++++++
2 files changed, 47 insertions(+), 20 deletions(-)
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index de30e86c72b48..031d25a9854fc 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -601,6 +601,25 @@ class _LIBCPP_TEMPLATE_VIS tuple
}
};
+ template
+ using _EnableImplicitTupleLikeConstructor = _EnableIf<
+ _CheckTupleLikeConstructor<
+ __tuple_like_with_size<_Tuple, sizeof...(_Tp)>::value
+ && !_PackExpandsToThisTuple<_Tuple>::value
+ && (!is_lvalue_reference<_Tuple>::value || !_DisableIfLValue)
+ >::template __enable_implicit<_Tuple>(),
+ bool
+ >;
+
+ template
+ using _EnableExplicitTupleLikeConstructor = _EnableIf<
+ _CheckTupleLikeConstructor<
+ __tuple_like_with_size<_Tuple, sizeof...(_Tp)>::value
+ && !_PackExpandsToThisTuple<_Tuple>::value
+ && (!is_lvalue_reference<_Tuple>::value || !_DisableIfLValue)
+ >::template __enable_explicit<_Tuple>(),
+ bool
+ >;
template friend _LIBCPP_CONSTEXPR_AFTER_CXX11
typename tuple_element<_Jp, tuple<_Up...> >::type& get(tuple<_Up...>&) _NOEXCEPT;
template friend _LIBCPP_CONSTEXPR_AFTER_CXX11
@@ -815,35 +834,27 @@ public:
typename __make_tuple_types::type(),
_VSTD::forward<_Up>(__u)...) {}
- template ::value
- && !_PackExpandsToThisTuple<_Tuple>::value
- >::template __enable_implicit<_Tuple>(),
- bool
- >::type = false
- >
+ template = false>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value))
: __base_(_VSTD::forward<_Tuple>(__t)) {}
- template ::value
- && !_PackExpandsToThisTuple<_Tuple>::value
- >::template __enable_explicit<_Tuple>(),
- bool
- >::type = false
- >
+ template = false>
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+ tuple(const _Tuple& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, const _Tuple&>::value))
+ : __base_(__t) {}
+ template = false>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
explicit
tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value))
: __base_(_VSTD::forward<_Tuple>(__t)) {}
+ template = false>
+ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+ explicit
+ tuple(const _Tuple& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, const _Tuple&>::value))
+ : __base_(__t) {}
+
template ::value>::type>
+ explicit ExplicitTwo(T) {}
+};
+
struct B
{
int id_;
@@ -136,6 +145,13 @@ int main(int, char**)
std::tuple t2 = t1;
assert(std::get<0>(t2).value == 42);
}
+ {
+ static_assert(std::is_convertible::value, "");
+ static_assert(std::is_convertible&&, const std::tuple&>::value, "");
+ ExplicitTwo e;
+ std::tuple t = std::tuple(std::move(e));
+ ((void)t);
+ }
return 0;
}
From 51a52b58930cd1bb2351bf7017adfd55073f6553 Mon Sep 17 00:00:00 2001
From: Nico Weber
Date: Fri, 12 Jul 2019 23:30:55 +0000
Subject: [PATCH 011/451] PDB HashTable: Move TraitsT from class parameter to
the methods that need it
The traits object is only used by a few methods. Deserializing a hash
table and walking it is possible without the traits object, so it
shouldn't be required to build a dummy object for that use case.
The TraitsT object used to be a function template parameter before
r327647, this restores it to that state.
This makes it clear that the traits object isn't needed at all in 1 of
the current 3 uses of HashTable (and I am going to add another use that
doesn't need it), and that the default PdbHashTraits isn't used outside
of tests.
While here, also re-enable 3 checks in the test that were commented out
(which requires making HashTableInternals templated and giving FooBar
an operator==).
No intended behavior change.
Differential Revision: https://reviews.llvm.org/D64640
llvm-svn: 365974
---
.../llvm/DebugInfo/PDB/Native/HashTable.h | 63 +++++-----
.../DebugInfo/PDB/Native/NamedStreamMap.h | 2 +-
.../DebugInfo/PDB/Native/PDBFileBuilder.h | 2 +-
.../DebugInfo/PDB/Native/NamedStreamMap.cpp | 7 +-
.../DebugInfo/PDB/Native/PDBFileBuilder.cpp | 5 +-
.../unittests/DebugInfo/PDB/HashTableTest.cpp | 119 ++++++++++--------
6 files changed, 102 insertions(+), 96 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/HashTable.h b/llvm/include/llvm/DebugInfo/PDB/Native/HashTable.h
index 86c43a482b820..b00873b575b20 100644
--- a/llvm/include/llvm/DebugInfo/PDB/Native/HashTable.h
+++ b/llvm/include/llvm/DebugInfo/PDB/Native/HashTable.h
@@ -31,21 +31,21 @@ namespace pdb {
Error readSparseBitVector(BinaryStreamReader &Stream, SparseBitVector<> &V);
Error writeSparseBitVector(BinaryStreamWriter &Writer, SparseBitVector<> &Vec);
-template class HashTable;
+template class HashTable;
-template
+template
class HashTableIterator
- : public iterator_facade_base,
+ : public iterator_facade_base,
std::forward_iterator_tag,
std::pair> {
- friend HashTable;
+ friend HashTable;
- HashTableIterator(const HashTable &Map, uint32_t Index,
+ HashTableIterator(const HashTable &Map, uint32_t Index,
bool IsEnd)
: Map(&Map), Index(Index), IsEnd(IsEnd) {}
public:
- HashTableIterator(const HashTable &Map) : Map(&Map) {
+ HashTableIterator(const HashTable &Map) : Map(&Map) {
int I = Map.Present.find_first();
if (I == -1) {
Index = 0;
@@ -87,22 +87,14 @@ class HashTableIterator
bool isEnd() const { return IsEnd; }
uint32_t index() const { return Index; }
- const HashTable *Map;
+ const HashTable *Map;
uint32_t Index;
bool IsEnd;
};
-template struct PdbHashTraits {};
-
-template <> struct PdbHashTraits {
- uint32_t hashLookupKey(uint32_t N) const { return N; }
- uint32_t storageKeyToLookupKey(uint32_t N) const { return N; }
- uint32_t lookupKeyToStorageKey(uint32_t N) { return N; }
-};
-
-template >
+template
class HashTable {
- using iterator = HashTableIterator;
+ using iterator = HashTableIterator;
friend iterator;
struct Header {
@@ -114,9 +106,7 @@ class HashTable {
public:
HashTable() { Buckets.resize(8); }
-
- explicit HashTable(TraitsT Traits) : HashTable(8, std::move(Traits)) {}
- HashTable(uint32_t Capacity, TraitsT Traits) : Traits(Traits) {
+ explicit HashTable(uint32_t Capacity) {
Buckets.resize(Capacity);
}
@@ -221,7 +211,8 @@ class HashTable {
/// Find the entry whose key has the specified hash value, using the specified
/// traits defining hash function and equality.
- template iterator find_as(const Key &K) const {
+ template
+ iterator find_as(const Key &K, TraitsT &Traits) const {
uint32_t H = Traits.hashLookupKey(K) % capacity();
uint32_t I = H;
Optional FirstUnused;
@@ -252,12 +243,14 @@ class HashTable {
/// Set the entry using a key type that the specified Traits can convert
/// from a real key to an internal key.
- template bool set_as(const Key &K, ValueT V) {
- return set_as_internal(K, std::move(V), None);
+ template
+ bool set_as(const Key &K, ValueT V, TraitsT &Traits) {
+ return set_as_internal(K, std::move(V), Traits, None);
}
- template ValueT get(const Key &K) const {
- auto Iter = find_as(K);
+ template
+ ValueT get(const Key &K, TraitsT &Traits) const {
+ auto Iter = find_as(K, Traits);
assert(Iter != end());
return (*Iter).second;
}
@@ -266,7 +259,6 @@ class HashTable {
bool isPresent(uint32_t K) const { return Present.test(K); }
bool isDeleted(uint32_t K) const { return Deleted.test(K); }
- TraitsT Traits;
BucketList Buckets;
mutable SparseBitVector<> Present;
mutable SparseBitVector<> Deleted;
@@ -274,9 +266,10 @@ class HashTable {
private:
/// Set the entry using a key type that the specified Traits can convert
/// from a real key to an internal key.
- template
- bool set_as_internal(const Key &K, ValueT V, Optional InternalKey) {
- auto Entry = find_as(K);
+ template
+ bool set_as_internal(const Key &K, ValueT V, TraitsT &Traits,
+ Optional InternalKey) {
+ auto Entry = find_as(K, Traits);
if (Entry != end()) {
assert(isPresent(Entry.index()));
assert(Traits.storageKeyToLookupKey(Buckets[Entry.index()].first) == K);
@@ -293,15 +286,16 @@ class HashTable {
Present.set(Entry.index());
Deleted.reset(Entry.index());
- grow();
+ grow(Traits);
- assert((find_as(K)) != end());
+ assert((find_as(K, Traits)) != end());
return true;
}
static uint32_t maxLoad(uint32_t capacity) { return capacity * 2 / 3 + 1; }
- void grow() {
+ template
+ void grow(TraitsT &Traits) {
uint32_t S = size();
uint32_t MaxLoad = maxLoad(capacity());
if (S < maxLoad(capacity()))
@@ -313,10 +307,11 @@ class HashTable {
// Growing requires rebuilding the table and re-hashing every item. Make a
// copy with a larger capacity, insert everything into the copy, then swap
// it in.
- HashTable NewMap(NewCapacity, Traits);
+ HashTable NewMap(NewCapacity);
for (auto I : Present) {
auto LookupKey = Traits.storageKeyToLookupKey(Buckets[I].first);
- NewMap.set_as_internal(LookupKey, Buckets[I].second, Buckets[I].first);
+ NewMap.set_as_internal(LookupKey, Buckets[I].second, Traits,
+ Buckets[I].first);
}
Buckets.swap(NewMap.Buckets);
diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h b/llvm/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h
index c49d796356c7b..1df059ffa9fda 100644
--- a/llvm/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h
+++ b/llvm/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h
@@ -59,7 +59,7 @@ class NamedStreamMap {
NamedStreamMapTraits HashTraits;
/// Closed hash table from Offset -> StreamNumber, where Offset is the offset
/// of the stream name in NamesBuffer.
- HashTable OffsetIndexMap;
+ HashTable OffsetIndexMap;
/// Buffer of string data.
std::vector NamesBuffer;
diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h b/llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h
index 72000bdc011ac..2abaa5f4cdc47 100644
--- a/llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h
+++ b/llvm/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h
@@ -97,7 +97,7 @@ class PDBFileBuilder {
PDBStringTableBuilder Strings;
StringTableHashTraits InjectedSourceHashTraits;
- HashTable InjectedSourceTable;
+ HashTable InjectedSourceTable;
SmallVector InjectedSources;
diff --git a/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp b/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
index 1c044e0c26538..4a88391494cd2 100644
--- a/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
@@ -46,8 +46,7 @@ uint32_t NamedStreamMapTraits::lookupKeyToStorageKey(StringRef S) {
return NS->appendStringData(S);
}
-NamedStreamMap::NamedStreamMap()
- : HashTraits(*this), OffsetIndexMap(1, HashTraits) {}
+NamedStreamMap::NamedStreamMap() : HashTraits(*this), OffsetIndexMap(1) {}
Error NamedStreamMap::load(BinaryStreamReader &Stream) {
uint32_t StringBufferSize;
@@ -99,7 +98,7 @@ uint32_t NamedStreamMap::hashString(uint32_t Offset) const {
}
bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
- auto Iter = OffsetIndexMap.find_as(Stream);
+ auto Iter = OffsetIndexMap.find_as(Stream, HashTraits);
if (Iter == OffsetIndexMap.end())
return false;
StreamNo = (*Iter).second;
@@ -123,5 +122,5 @@ uint32_t NamedStreamMap::appendStringData(StringRef S) {
}
void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
- OffsetIndexMap.set_as(Stream, support::ulittle32_t(StreamNo));
+ OffsetIndexMap.set_as(Stream, support::ulittle32_t(StreamNo), HashTraits);
}
diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
index 84eb4fbbfa631..8f5a048ea4b56 100644
--- a/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
@@ -34,7 +34,7 @@ using namespace llvm::support;
PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
: Allocator(Allocator), InjectedSourceHashTraits(Strings),
- InjectedSourceTable(2, InjectedSourceHashTraits) {}
+ InjectedSourceTable(2) {}
PDBFileBuilder::~PDBFileBuilder() {}
@@ -189,7 +189,8 @@ Error PDBFileBuilder::finalizeMsfLayout() {
static_cast(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
Entry.CRC = CRC.getCRC();
StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex);
- InjectedSourceTable.set_as(VName, std::move(Entry));
+ InjectedSourceTable.set_as(VName, std::move(Entry),
+ InjectedSourceHashTraits);
}
uint32_t SrcHeaderBlockSize =
diff --git a/llvm/unittests/DebugInfo/PDB/HashTableTest.cpp b/llvm/unittests/DebugInfo/PDB/HashTableTest.cpp
index 4ebde45ff9a62..5f0695bc4cb22 100644
--- a/llvm/unittests/DebugInfo/PDB/HashTableTest.cpp
+++ b/llvm/unittests/DebugInfo/PDB/HashTableTest.cpp
@@ -27,27 +27,35 @@ using namespace llvm::support;
namespace {
-class HashTableInternals : public HashTable {
+struct IdentityHashTraits {
+ uint32_t hashLookupKey(uint32_t N) const { return N; }
+ uint32_t storageKeyToLookupKey(uint32_t N) const { return N; }
+ uint32_t lookupKeyToStorageKey(uint32_t N) { return N; }
+};
+
+template
+class HashTableInternals : public HashTable {
public:
- using HashTable::Buckets;
- using HashTable::Present;
- using HashTable::Deleted;
+ using HashTable::Buckets;
+ using HashTable::Present;
+ using HashTable::Deleted;
};
}
TEST(HashTableTest, TestSimple) {
- HashTableInternals Table;
+ HashTableInternals<> Table;
EXPECT_EQ(0u, Table.size());
EXPECT_GT(Table.capacity(), 0u);
- Table.set_as(3u, 7);
+ IdentityHashTraits Traits;
+ Table.set_as(3u, 7, Traits);
EXPECT_EQ(1u, Table.size());
- ASSERT_NE(Table.end(), Table.find_as(3u));
- EXPECT_EQ(7u, Table.get(3u));
+ ASSERT_NE(Table.end(), Table.find_as(3u, Traits));
+ EXPECT_EQ(7u, Table.get(3u, Traits));
}
TEST(HashTableTest, TestCollision) {
- HashTableInternals Table;
+ HashTableInternals<> Table;
EXPECT_EQ(0u, Table.size());
EXPECT_GT(Table.capacity(), 0u);
@@ -57,33 +65,35 @@ TEST(HashTableTest, TestCollision) {
uint32_t N1 = Table.capacity() + 1;
uint32_t N2 = 2 * N1;
- Table.set_as(N1, 7);
- Table.set_as(N2, 12);
+ IdentityHashTraits Traits;
+ Table.set_as(N1, 7, Traits);
+ Table.set_as(N2, 12, Traits);
EXPECT_EQ(2u, Table.size());
- ASSERT_NE(Table.end(), Table.find_as(N1));
- ASSERT_NE(Table.end(), Table.find_as(N2));
+ ASSERT_NE(Table.end(), Table.find_as(N1, Traits));
+ ASSERT_NE(Table.end(), Table.find_as(N2, Traits));
- EXPECT_EQ(7u, Table.get(N1));
- EXPECT_EQ(12u, Table.get(N2));
+ EXPECT_EQ(7u, Table.get(N1, Traits));
+ EXPECT_EQ(12u, Table.get(N2, Traits));
}
TEST(HashTableTest, TestRemove) {
- HashTableInternals Table;
+ HashTableInternals<> Table;
EXPECT_EQ(0u, Table.size());
EXPECT_GT(Table.capacity(), 0u);
- Table.set_as(1u, 2);
- Table.set_as(3u, 4);
+ IdentityHashTraits Traits;
+ Table.set_as(1u, 2, Traits);
+ Table.set_as(3u, 4, Traits);
EXPECT_EQ(2u, Table.size());
- ASSERT_NE(Table.end(), Table.find_as(1u));
- ASSERT_NE(Table.end(), Table.find_as(3u));
+ ASSERT_NE(Table.end(), Table.find_as(1u, Traits));
+ ASSERT_NE(Table.end(), Table.find_as(3u, Traits));
- EXPECT_EQ(2u, Table.get(1u));
- EXPECT_EQ(4u, Table.get(3u));
+ EXPECT_EQ(2u, Table.get(1u, Traits));
+ EXPECT_EQ(4u, Table.get(3u, Traits));
}
TEST(HashTableTest, TestCollisionAfterMultipleProbes) {
- HashTableInternals Table;
+ HashTableInternals<> Table;
EXPECT_EQ(0u, Table.size());
EXPECT_GT(Table.capacity(), 0u);
@@ -94,17 +104,18 @@ TEST(HashTableTest, TestCollisionAfterMultipleProbes) {
uint32_t N2 = N1 + 1;
uint32_t N3 = 2 * N1;
- Table.set_as(N1, 7);
- Table.set_as(N2, 11);
- Table.set_as(N3, 13);
+ IdentityHashTraits Traits;
+ Table.set_as(N1, 7, Traits);
+ Table.set_as(N2, 11, Traits);
+ Table.set_as(N3, 13, Traits);
EXPECT_EQ(3u, Table.size());
- ASSERT_NE(Table.end(), Table.find_as(N1));
- ASSERT_NE(Table.end(), Table.find_as(N2));
- ASSERT_NE(Table.end(), Table.find_as(N3));
+ ASSERT_NE(Table.end(), Table.find_as(N1, Traits));
+ ASSERT_NE(Table.end(), Table.find_as(N2, Traits));
+ ASSERT_NE(Table.end(), Table.find_as(N3, Traits));
- EXPECT_EQ(7u, Table.get(N1));
- EXPECT_EQ(11u, Table.get(N2));
- EXPECT_EQ(13u, Table.get(N3));
+ EXPECT_EQ(7u, Table.get(N1, Traits));
+ EXPECT_EQ(11u, Table.get(N2, Traits));
+ EXPECT_EQ(13u, Table.get(N3, Traits));
}
TEST(HashTableTest, Grow) {
@@ -112,24 +123,26 @@ TEST(HashTableTest, Grow) {
// guaranteed to trigger a grow. Then verify that the size is the same, the
// capacity is larger, and all the original items are still in the table.
- HashTableInternals Table;
+ HashTableInternals<> Table;
+ IdentityHashTraits Traits;
uint32_t OldCapacity = Table.capacity();
for (uint32_t I = 0; I < OldCapacity; ++I) {
- Table.set_as(OldCapacity + I * 2 + 1, I * 2 + 3);
+ Table.set_as(OldCapacity + I * 2 + 1, I * 2 + 3, Traits);
}
EXPECT_EQ(OldCapacity, Table.size());
EXPECT_GT(Table.capacity(), OldCapacity);
for (uint32_t I = 0; I < OldCapacity; ++I) {
- ASSERT_NE(Table.end(), Table.find_as(OldCapacity + I * 2 + 1));
- EXPECT_EQ(I * 2 + 3, Table.get(OldCapacity + I * 2 + 1));
+ ASSERT_NE(Table.end(), Table.find_as(OldCapacity + I * 2 + 1, Traits));
+ EXPECT_EQ(I * 2 + 3, Table.get(OldCapacity + I * 2 + 1, Traits));
}
}
TEST(HashTableTest, Serialization) {
- HashTableInternals Table;
+ HashTableInternals<> Table;
+ IdentityHashTraits Traits;
uint32_t Cap = Table.capacity();
for (uint32_t I = 0; I < Cap; ++I) {
- Table.set_as(Cap + I * 2 + 1, I * 2 + 3);
+ Table.set_as(Cap + I * 2 + 1, I * 2 + 3, Traits);
}
std::vector Buffer(Table.calculateSerializedLength());
@@ -139,7 +152,7 @@ TEST(HashTableTest, Serialization) {
// We should have written precisely the number of bytes we calculated earlier.
EXPECT_EQ(Buffer.size(), Writer.getOffset());
- HashTableInternals Table2;
+ HashTableInternals<> Table2;
BinaryStreamReader Reader(Stream);
EXPECT_THAT_ERROR(Table2.load(Reader), Succeeded());
// We should have read precisely the number of bytes we calculated earlier.
@@ -192,20 +205,19 @@ TEST(HashTableTest, NamedStreamMap) {
} while (std::next_permutation(Streams.begin(), Streams.end()));
}
-namespace {
struct FooBar {
uint32_t X;
uint32_t Y;
-};
-} // namespace
+ bool operator==(const FooBar &RHS) const {
+ return X == RHS.X && Y == RHS.Y;
+ }
+};
-namespace llvm {
-namespace pdb {
-template <> struct PdbHashTraits {
+struct FooBarHashTraits {
std::vector Buffer;
- PdbHashTraits() { Buffer.push_back(0); }
+ FooBarHashTraits() { Buffer.push_back(0); }
uint32_t hashLookupKey(StringRef S) const {
return llvm::pdb::hashStringV1(S);
@@ -225,17 +237,16 @@ template <> struct PdbHashTraits {
return N;
}
};
-} // namespace pdb
-} // namespace llvm
TEST(HashTableTest, NonTrivialValueType) {
- HashTable Table;
+ HashTableInternals Table;
+ FooBarHashTraits Traits;
uint32_t Cap = Table.capacity();
for (uint32_t I = 0; I < Cap; ++I) {
FooBar F;
F.X = I;
F.Y = I + 1;
- Table.set_as(utostr(I), F);
+ Table.set_as(utostr(I), F, Traits);
}
std::vector Buffer(Table.calculateSerializedLength());
@@ -245,7 +256,7 @@ TEST(HashTableTest, NonTrivialValueType) {
// We should have written precisely the number of bytes we calculated earlier.
EXPECT_EQ(Buffer.size(), Writer.getOffset());
- HashTable Table2;
+ HashTableInternals Table2;
BinaryStreamReader Reader(Stream);
EXPECT_THAT_ERROR(Table2.load(Reader), Succeeded());
// We should have read precisely the number of bytes we calculated earlier.
@@ -253,7 +264,7 @@ TEST(HashTableTest, NonTrivialValueType) {
EXPECT_EQ(Table.size(), Table2.size());
EXPECT_EQ(Table.capacity(), Table2.capacity());
- // EXPECT_EQ(Table.Buckets, Table2.Buckets);
- // EXPECT_EQ(Table.Present, Table2.Present);
- // EXPECT_EQ(Table.Deleted, Table2.Deleted);
+ EXPECT_EQ(Table.Buckets, Table2.Buckets);
+ EXPECT_EQ(Table.Present, Table2.Present);
+ EXPECT_EQ(Table.Deleted, Table2.Deleted);
}
From 5d9d7c59ee3353675ec89653c3a2b0175305d59a Mon Sep 17 00:00:00 2001
From: Sam McCall
Date: Fri, 12 Jul 2019 23:38:31 +0000
Subject: [PATCH 012/451] Re-land [JSONCompilationDatabase] Strip
distcc/ccache/gomacc wrappers from parsed commands.
Use //net/dir like other test cases for windows compatibility
llvm-svn: 365975
---
clang/lib/Tooling/JSONCompilationDatabase.cpp | 50 +++++++++++++++++--
.../Tooling/CompilationDatabaseTest.cpp | 27 ++++++++++
2 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp
index 76a82b0fd9bd3..f19a0f7550b96 100644
--- a/clang/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp
@@ -256,15 +256,57 @@ JSONCompilationDatabase::getAllCompileCommands() const {
return Commands;
}
+static llvm::StringRef stripExecutableExtension(llvm::StringRef Name) {
+ Name.consume_back(".exe");
+ return Name;
+}
+
+// There are compiler-wrappers (ccache, distcc, gomacc) that take the "real"
+// compiler as an argument, e.g. distcc gcc -O3 foo.c.
+// These end up in compile_commands.json when people set CC="distcc gcc".
+// Clang's driver doesn't understand this, so we need to unwrap.
+static bool unwrapCommand(std::vector &Args) {
+ if (Args.size() < 2)
+ return false;
+ StringRef Wrapper =
+ stripExecutableExtension(llvm::sys::path::filename(Args.front()));
+ if (Wrapper == "distcc" || Wrapper == "gomacc" || Wrapper == "ccache") {
+ // Most of these wrappers support being invoked 3 ways:
+ // `distcc g++ file.c` This is the mode we're trying to match.
+ // We need to drop `distcc`.
+ // `distcc file.c` This acts like compiler is cc or similar.
+ // Clang's driver can handle this, no change needed.
+ // `g++ file.c` g++ is a symlink to distcc.
+ // We don't even notice this case, and all is well.
+ //
+ // We need to distinguish between the first and second case.
+ // The wrappers themselves don't take flags, so Args[1] is a compiler flag,
+ // an input file, or a compiler. Inputs have extensions, compilers don't.
+ bool HasCompiler =
+ (Args[1][0] != '-') &&
+ !llvm::sys::path::has_extension(stripExecutableExtension(Args[1]));
+ if (HasCompiler) {
+ Args.erase(Args.begin());
+ return true;
+ }
+ // If !HasCompiler, wrappers act like GCC. Fine: so do we.
+ }
+ return false;
+}
+
static std::vector
nodeToCommandLine(JSONCommandLineSyntax Syntax,
const std::vector &Nodes) {
SmallString<1024> Storage;
- if (Nodes.size() == 1)
- return unescapeCommandLine(Syntax, Nodes[0]->getValue(Storage));
std::vector Arguments;
- for (const auto *Node : Nodes)
- Arguments.push_back(Node->getValue(Storage));
+ if (Nodes.size() == 1)
+ Arguments = unescapeCommandLine(Syntax, Nodes[0]->getValue(Storage));
+ else
+ for (const auto *Node : Nodes)
+ Arguments.push_back(Node->getValue(Storage));
+ // There may be multiple wrappers: using distcc and ccache together is common.
+ while (unwrapCommand(Arguments))
+ ;
return Arguments;
}
diff --git a/clang/unittests/Tooling/CompilationDatabaseTest.cpp b/clang/unittests/Tooling/CompilationDatabaseTest.cpp
index da7ae09917dfa..fde95445bdab0 100644
--- a/clang/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/clang/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -370,6 +370,33 @@ TEST(findCompileArgsInJsonDatabase, FindsEntry) {
EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
}
+TEST(findCompileArgsInJsonDatabase, ParsesCompilerWrappers) {
+ StringRef Directory("//net/dir");
+ StringRef FileName("//net/dir/filename");
+ std::vector> Cases = {
+ {"distcc gcc foo.c", "gcc foo.c"},
+ {"gomacc clang++ foo.c", "clang++ foo.c"},
+ {"ccache gcc foo.c", "gcc foo.c"},
+ {"ccache.exe gcc foo.c", "gcc foo.c"},
+ {"ccache g++.exe foo.c", "g++.exe foo.c"},
+ {"ccache distcc gcc foo.c", "gcc foo.c"},
+
+ {"distcc foo.c", "distcc foo.c"},
+ {"distcc -I/foo/bar foo.c", "distcc -I/foo/bar foo.c"},
+ };
+ std::string ErrorMessage;
+
+ for (const auto &Case : Cases) {
+ std::string DB =
+ R"([{"directory":"//net/dir", "file":"//net/dir/foo.c", "command":")" +
+ Case.first + "\"}]";
+ CompileCommand FoundCommand =
+ findCompileArgsInJsonDatabase("//net/dir/foo.c", DB, ErrorMessage);
+ EXPECT_EQ(Case.second, llvm::join(FoundCommand.CommandLine, " "))
+ << Case.first;
+ }
+}
+
static std::vector unescapeJsonCommandLine(StringRef Command) {
std::string JsonDatabase =
("[{\"directory\":\"//net/root\", \"file\":\"test\", \"command\": \"" +
From 4765aa14ff429db9301047296c9bd8e201bcb3a2 Mon Sep 17 00:00:00 2001
From: Jan Korous
Date: Sat, 13 Jul 2019 00:09:04 +0000
Subject: [PATCH 013/451] [DirectoryWatcher][test][NFC] Add information to test
failure reports
llvm-svn: 365976
---
.../DirectoryWatcher/DirectoryWatcherTest.cpp | 27 +++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp b/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp
index 0808ff47dee89..72bc86d4493cf 100644
--- a/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp
+++ b/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp
@@ -97,7 +97,9 @@ std::string eventKindToString(const DirectoryWatcher::Event::EventKind K) {
struct VerifyingConsumer {
std::vector ExpectedInitial;
+ const std::vector ExpectedInitialCopy;
std::vector ExpectedNonInitial;
+ const std::vector ExpectedNonInitialCopy;
std::vector OptionalNonInitial;
std::vector UnexpectedInitial;
std::vector UnexpectedNonInitial;
@@ -108,8 +110,8 @@ struct VerifyingConsumer {
const std::vector &ExpectedInitial,
const std::vector &ExpectedNonInitial,
const std::vector &OptionalNonInitial = {})
- : ExpectedInitial(ExpectedInitial),
- ExpectedNonInitial(ExpectedNonInitial),
+ : ExpectedInitial(ExpectedInitial), ExpectedInitialCopy(ExpectedInitial),
+ ExpectedNonInitial(ExpectedNonInitial), ExpectedNonInitialCopy(ExpectedNonInitial),
OptionalNonInitial(OptionalNonInitial) {}
// This method is used by DirectoryWatcher.
@@ -181,6 +183,26 @@ struct VerifyingConsumer {
}
void printUnmetExpectations(llvm::raw_ostream &OS) {
+ // If there was any issue, print the expected state
+ if (
+ !ExpectedInitial.empty()
+ ||
+ !ExpectedNonInitial.empty()
+ ||
+ !UnexpectedInitial.empty()
+ ||
+ !UnexpectedNonInitial.empty()
+ ) {
+ OS << "Expected initial events: \n";
+ for (const auto &E : ExpectedInitialCopy) {
+ OS << eventKindToString(E.Kind) << " " << E.Filename << "\n";
+ }
+ OS << "Expected non-initial events: \n";
+ for (const auto &E : ExpectedNonInitialCopy) {
+ OS << eventKindToString(E.Kind) << " " << E.Filename << "\n";
+ }
+ }
+
if (!ExpectedInitial.empty()) {
OS << "Expected but not seen initial events: \n";
for (const auto &E : ExpectedInitial) {
@@ -218,6 +240,7 @@ void checkEventualResultWithTimeout(VerifyingConsumer &TestConsumer) {
EXPECT_TRUE(WaitForExpectedStateResult.wait_for(std::chrono::seconds(3)) ==
std::future_status::ready)
<< "The expected result state wasn't reached before the time-out.";
+ std::unique_lock L(TestConsumer.Mtx);
EXPECT_TRUE(TestConsumer.result().hasValue());
if (TestConsumer.result().hasValue()) {
EXPECT_TRUE(*TestConsumer.result());
From de85380fa02506ebb7ebbd46b4eb3d80f5619e38 Mon Sep 17 00:00:00 2001
From: Johannes Doerfert
Date: Sat, 13 Jul 2019 00:09:27 +0000
Subject: [PATCH 014/451] [Attributor][FIX] Lookup of (call site) argument
attributes
llvm-svn: 365977
---
llvm/include/llvm/Transforms/IPO/Attributor.h | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 3a8e88bd20ff5..0b72394e8e9ec 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -179,9 +179,12 @@ struct Attributor {
assert(AAType::ID != Attribute::None &&
"Cannot lookup generic abstract attributes!");
- // Determine the argument number automatically for llvm::Arguments.
+ // Determine the argument number automatically for llvm::Arguments if none
+ // is set. Do not override a given one as it could be a use of the argument
+ // in a call site.
if (auto *Arg = dyn_cast(&V))
- ArgNo = Arg->getArgNo();
+ if (ArgNo == -1)
+ ArgNo = Arg->getArgNo();
// If a function was given together with an argument number, perform the
// lookup for the actual argument instead. Don't do it for variadic
From b016de51e04fbade2b14d74e36b2cfc6edde9394 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere
Date: Sat, 13 Jul 2019 00:12:22 +0000
Subject: [PATCH 015/451] [DWARFContext] Strip leading dot in section names
The LLVM context doesn't expect the leading dot in the section name.
llvm-svn: 365978
---
lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp
index 2f693fe5c3243..eb307ce1cce1b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp
@@ -116,6 +116,8 @@ llvm::DWARFContext &DWARFContext::GetAsLLVM() {
llvm::StringRef data = llvm::toStringRef(section_data.GetData());
llvm::StringRef name = section.GetName().GetStringRef();
+ if (name.startswith("."))
+ name = name.drop_front();
section_map.try_emplace(
name, llvm::MemoryBuffer::getMemBuffer(data, name, false));
};
From 0291d309291f69525fdf61072b6790fd5e1d67bf Mon Sep 17 00:00:00 2001
From: Reid Kleckner
Date: Sat, 13 Jul 2019 00:20:34 +0000
Subject: [PATCH 016/451] [COFF] Add null check in case of symbols defined in
LTO blobs
The test case could probably be improved further if the failure path was
better understood.
Fixes PR42536
llvm-svn: 365979
---
lld/COFF/SymbolTable.cpp | 2 +-
.../COFF/Inputs/undefined-symbol-lto-a.ll | 82 +++++++++++++++++++
.../COFF/Inputs/undefined-symbol-lto-b.ll | 29 +++++++
lld/test/COFF/undefined-symbol-lto.test | 30 +++++++
4 files changed, 142 insertions(+), 1 deletion(-)
create mode 100644 lld/test/COFF/Inputs/undefined-symbol-lto-a.ll
create mode 100644 lld/test/COFF/Inputs/undefined-symbol-lto-b.ll
create mode 100644 lld/test/COFF/undefined-symbol-lto.test
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 280a9c28892c8..2173c10c1ca56 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -69,7 +69,7 @@ static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {
for (Symbol *s : sc->file->getSymbols()) {
auto *d = dyn_cast_or_null(s);
- if (!d || d->getChunk() != sc || d->getValue() > addr ||
+ if (!d || !d->data || d->getChunk() != sc || d->getValue() > addr ||
(candidate && d->getValue() < candidate->getValue()))
continue;
diff --git a/lld/test/COFF/Inputs/undefined-symbol-lto-a.ll b/lld/test/COFF/Inputs/undefined-symbol-lto-a.ll
new file mode 100644
index 0000000000000..6793ec718e806
--- /dev/null
+++ b/lld/test/COFF/Inputs/undefined-symbol-lto-a.ll
@@ -0,0 +1,82 @@
+; ModuleID = 't.obj'
+source_filename = "t.cpp"
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.21.27702"
+
+%struct.Init = type { %struct.S }
+%struct.S = type { i32 (...)** }
+%rtti.CompleteObjectLocator = type { i32, i32, i32, i32, i32, i32 }
+%rtti.TypeDescriptor7 = type { i8**, i8*, [8 x i8] }
+%rtti.ClassHierarchyDescriptor = type { i32, i32, i32, i32 }
+%rtti.BaseClassDescriptor = type { i32, i32, i32, i32, i32, i32, i32 }
+
+$"??_SS@@6B@" = comdat largest
+
+$"??_R4S@@6B@" = comdat any
+
+$"??_R0?AUS@@@8" = comdat any
+
+$"??_R3S@@8" = comdat any
+
+$"??_R2S@@8" = comdat any
+
+$"??_R1A@?0A@EA@S@@8" = comdat any
+
+@"?d@@3UInit@@A" = dso_local local_unnamed_addr global %struct.Init zeroinitializer, align 8
+@anon.bcb2691509de99310dddb690fcdb4cdc.0 = private unnamed_addr constant { [2 x i8*] } { [2 x i8*] [i8* bitcast (%rtti.CompleteObjectLocator* @"??_R4S@@6B@" to i8*), i8* bitcast (void (%struct.S*)* @"?foo@S@@UEAAXXZ" to i8*)] }, comdat($"??_SS@@6B@"), !type !0
+@"??_R4S@@6B@" = linkonce_odr constant %rtti.CompleteObjectLocator { i32 1, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"??_R0?AUS@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"??_R3S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.CompleteObjectLocator* @"??_R4S@@6B@" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat
+@"??_7type_info@@6B@" = external constant i8*
+@"??_R0?AUS@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"??_7type_info@@6B@", i8* null, [8 x i8] c".?AUS@@\00" }, comdat
+@__ImageBase = external dso_local constant i8
+@"??_R3S@@8" = linkonce_odr constant %rtti.ClassHierarchyDescriptor { i32 0, i32 0, i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint ([2 x i32]* @"??_R2S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat
+@"??_R2S@@8" = linkonce_odr constant [2 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.BaseClassDescriptor* @"??_R1A@?0A@EA@S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0], comdat
+@"??_R1A@?0A@EA@S@@8" = linkonce_odr constant %rtti.BaseClassDescriptor { i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"??_R0?AUS@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 0, i32 -1, i32 0, i32 64, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"??_R3S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat
+@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_t.cpp, i8* null }]
+
+@"??_SS@@6B@" = unnamed_addr alias i8*, getelementptr inbounds ({ [2 x i8*] }, { [2 x i8*] }* @anon.bcb2691509de99310dddb690fcdb4cdc.0, i32 0, i32 0, i32 1)
+
+declare dso_local void @"?undefined_ref@@YAXXZ"() local_unnamed_addr #0
+
+declare dllimport void @"?foo@S@@UEAAXXZ"(%struct.S*) unnamed_addr #0
+
+; Function Attrs: nounwind sspstrong uwtable
+define internal void @_GLOBAL__sub_I_t.cpp() #1 {
+entry:
+ store i32 (...)** bitcast (i8** @"??_SS@@6B@" to i32 (...)**), i32 (...)*** getelementptr inbounds (%struct.Init, %struct.Init* @"?d@@3UInit@@A", i64 0, i32 0, i32 0), align 8
+ tail call void @"?undefined_ref@@YAXXZ"() #2
+ ret void
+}
+
+attributes #0 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind }
+
+!llvm.linker.options = !{!1, !2}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = !{i64 8, !"?AUS@@"}
+!1 = !{!"/DEFAULTLIB:libcmt.lib"}
+!2 = !{!"/DEFAULTLIB:oldnames.lib"}
+!3 = !{i32 1, !"wchar_size", i32 2}
+!4 = !{i32 7, !"PIC Level", i32 2}
+!5 = !{i32 1, !"ThinLTO", i32 0}
+!6 = !{i32 1, !"EnableSplitLTOUnit", i32 0}
+!7 = !{!"clang version 9.0.0 (git@github.com:llvm/llvm-project.git 1a285c27fdf6407ceed3398e015d00559f5f533d)"}
+
+^0 = module: (path: "t.obj", hash: (0, 0, 0, 0, 0))
+^1 = gv: (name: "__ImageBase") ; guid = 434928772013489304
+^2 = gv: (name: "??_R2S@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^1, ^6)))) ; guid = 2160898732728284029
+^3 = gv: (name: "llvm.global_ctors", summaries: (variable: (module: ^0, flags: (linkage: appending, notEligibleToImport: 1, live: 1, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^14)))) ; guid = 2412314959268824392
+^4 = gv: (name: "?foo@S@@UEAAXXZ") ; guid = 6578172636330484861
+^5 = gv: (name: "??_SS@@6B@", summaries: (alias: (module: ^0, flags: (linkage: external, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), aliasee: ^10))) ; guid = 8774897714842691026
+^6 = gv: (name: "??_R1A@?0A@EA@S@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^11, ^1, ^8)))) ; guid = 9397802696236423453
+^7 = gv: (name: "?undefined_ref@@YAXXZ") ; guid = 9774674600202276560
+^8 = gv: (name: "??_R3S@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^1, ^2)))) ; guid = 10685958509605791599
+^9 = gv: (name: "??_7type_info@@6B@") ; guid = 10826752452437539368
+^10 = gv: (name: "anon.bcb2691509de99310dddb690fcdb4cdc.0", summaries: (variable: (module: ^0, flags: (linkage: private, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), vTableFuncs: ((virtFunc: ^4, offset: 8)), refs: (^13, ^4)))) ; guid = 11510395461204283992
+^11 = gv: (name: "??_R0?AUS@@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^9)))) ; guid = 12346607659584231960
+^12 = gv: (name: "?d@@3UInit@@A", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1)))) ; guid = 14563354643524156382
+^13 = gv: (name: "??_R4S@@6B@", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^13, ^11, ^1, ^8)))) ; guid = 14703528065171087394
+^14 = gv: (name: "_GLOBAL__sub_I_t.cpp", summaries: (function: (module: ^0, flags: (linkage: internal, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 3, calls: ((callee: ^7)), refs: (^12, ^5)))) ; guid = 15085897428757412588
+^15 = typeidCompatibleVTable: (name: "?AUS@@", summary: ((offset: 8, ^10))) ; guid = 13986515119763165370
diff --git a/lld/test/COFF/Inputs/undefined-symbol-lto-b.ll b/lld/test/COFF/Inputs/undefined-symbol-lto-b.ll
new file mode 100644
index 0000000000000..ff73e7c6ba680
--- /dev/null
+++ b/lld/test/COFF/Inputs/undefined-symbol-lto-b.ll
@@ -0,0 +1,29 @@
+; ModuleID = 'b.obj'
+source_filename = "b.cpp"
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.21.27702"
+
+%struct.S = type { i32 (...)** }
+
+; Function Attrs: norecurse nounwind readnone sspstrong uwtable
+define dso_local void @"?foo@S@@UEAAXXZ"(%struct.S* nocapture %this) unnamed_addr #0 align 2 {
+entry:
+ ret void
+}
+
+attributes #0 = { norecurse nounwind readnone sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.linker.options = !{!0, !1}
+!llvm.module.flags = !{!2, !3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = !{!"/DEFAULTLIB:libcmt.lib"}
+!1 = !{!"/DEFAULTLIB:oldnames.lib"}
+!2 = !{i32 1, !"wchar_size", i32 2}
+!3 = !{i32 7, !"PIC Level", i32 2}
+!4 = !{i32 1, !"ThinLTO", i32 0}
+!5 = !{i32 1, !"EnableSplitLTOUnit", i32 0}
+!6 = !{!"clang version 9.0.0 (git@github.com:llvm/llvm-project.git 1a285c27fdf6407ceed3398e015d00559f5f533d)"}
+
+^0 = module: (path: "b.obj", hash: (0, 0, 0, 0, 0))
+^1 = gv: (name: "?foo@S@@UEAAXXZ", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 1, funcFlags: (readNone: 1, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 0)))) ; guid = 6578172636330484861
diff --git a/lld/test/COFF/undefined-symbol-lto.test b/lld/test/COFF/undefined-symbol-lto.test
new file mode 100644
index 0000000000000..6911b121122a4
--- /dev/null
+++ b/lld/test/COFF/undefined-symbol-lto.test
@@ -0,0 +1,30 @@
+RUN: rm -rf %t && mkdir -p %t && cd %t
+RUN: llvm-as %S/Inputs/undefined-symbol-lto-a.ll -o t.obj
+RUN: llvm-as %S/Inputs/undefined-symbol-lto-b.ll -o b.obj
+RUN: llvm-lib b.obj -out:b.lib
+RUN: not lld-link t.obj b.lib -subsystem:console 2>&1 | FileCheck %s
+
+CHECK: undefined symbol: main
+CHECK: referenced by
+CHECK: undefined symbol: void __cdecl undefined_ref(void)
+CHECK: referenced by
+
+Originally reported as PR42536.
+
+a.ll corresponds to this C++:
+
+struct __declspec(dllimport) S {
+ virtual void foo();
+};
+void undefined_ref();
+struct Init {
+ Init() { undefined_ref(); }
+ S c;
+} d;
+
+b.ll is from this C++:
+
+struct S {
+ virtual void foo();
+};
+void S::foo() {}
From 41c22b4390c763f6fc36ec984f3786d465c434b5 Mon Sep 17 00:00:00 2001
From: Evgeniy Stepanov
Date: Sat, 13 Jul 2019 00:29:03 +0000
Subject: [PATCH 017/451] Extend function attributes bitset size from 64 to 96.
Summary: We are going to add a function attribute number 64.
Reviewers: pcc, jdoerfert, lebedev.ri
Subscribers: hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D64663
llvm-svn: 365980
---
llvm/lib/IR/AttributeImpl.h | 12 ++++++------
llvm/lib/IR/Attributes.cpp | 17 ++++++++++++-----
2 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/IR/AttributeImpl.h b/llvm/lib/IR/AttributeImpl.h
index f6898476382dd..f989fa3b910e6 100644
--- a/llvm/lib/IR/AttributeImpl.h
+++ b/llvm/lib/IR/AttributeImpl.h
@@ -179,9 +179,9 @@ class AttributeSetNode final
private TrailingObjects {
friend TrailingObjects;
- /// Bitset with a bit for each available attribute Attribute::AttrKind.
- uint64_t AvailableAttrs;
unsigned NumAttrs; ///< Number of attributes in this node.
+ /// Bitset with a bit for each available attribute Attribute::AttrKind.
+ uint8_t AvailableAttrs[12] = {};
AttributeSetNode(ArrayRef Attrs);
@@ -200,7 +200,7 @@ class AttributeSetNode final
unsigned getNumAttributes() const { return NumAttrs; }
bool hasAttribute(Attribute::AttrKind Kind) const {
- return AvailableAttrs & ((uint64_t)1) << Kind;
+ return AvailableAttrs[Kind / 8] & ((uint64_t)1) << (Kind % 8);
}
bool hasAttribute(StringRef Kind) const;
bool hasAttributes() const { return NumAttrs != 0; }
@@ -244,10 +244,10 @@ class AttributeListImpl final
friend TrailingObjects;
private:
- /// Bitset with a bit for each available attribute Attribute::AttrKind.
- uint64_t AvailableFunctionAttrs;
LLVMContext &Context;
unsigned NumAttrSets; ///< Number of entries in this set.
+ /// Bitset with a bit for each available attribute Attribute::AttrKind.
+ uint8_t AvailableFunctionAttrs[12] = {};
// Helper fn for TrailingObjects class.
size_t numTrailingObjects(OverloadToken) { return NumAttrSets; }
@@ -267,7 +267,7 @@ class AttributeListImpl final
/// Return true if the AttributeSet or the FunctionIndex has an
/// enum attribute of the given kind.
bool hasFnAttribute(Attribute::AttrKind Kind) const {
- return AvailableFunctionAttrs & ((uint64_t)1) << Kind;
+ return AvailableFunctionAttrs[Kind / 8] & ((uint64_t)1) << (Kind % 8);
}
using iterator = const AttributeSet *;
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 90b3c22e80f01..1ba703bb14c76 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -718,13 +718,18 @@ LLVM_DUMP_METHOD void AttributeSet::dump() const {
//===----------------------------------------------------------------------===//
AttributeSetNode::AttributeSetNode(ArrayRef Attrs)
- : AvailableAttrs(0), NumAttrs(Attrs.size()) {
+ : NumAttrs(Attrs.size()) {
// There's memory after the node where we can store the entries in.
llvm::copy(Attrs, getTrailingObjects());
+ static_assert(Attribute::EndAttrKinds <=
+ sizeof(AvailableAttrs) * CHAR_BIT,
+ "Too many attributes");
+
for (const auto I : *this) {
if (!I.isStringAttribute()) {
- AvailableAttrs |= ((uint64_t)1) << I.getKindAsEnum();
+ Attribute::AttrKind Kind = I.getKindAsEnum();
+ AvailableAttrs[Kind / 8] |= 1ULL << (Kind % 8);
}
}
}
@@ -896,7 +901,7 @@ static constexpr unsigned attrIdxToArrayIdx(unsigned Index) {
AttributeListImpl::AttributeListImpl(LLVMContext &C,
ArrayRef Sets)
- : AvailableFunctionAttrs(0), Context(C), NumAttrSets(Sets.size()) {
+ : Context(C), NumAttrSets(Sets.size()) {
assert(!Sets.empty() && "pointless AttributeListImpl");
// There's memory after the node where we can store the entries in.
@@ -909,8 +914,10 @@ AttributeListImpl::AttributeListImpl(LLVMContext &C,
static_assert(attrIdxToArrayIdx(AttributeList::FunctionIndex) == 0U,
"function should be stored in slot 0");
for (const auto I : Sets[0]) {
- if (!I.isStringAttribute())
- AvailableFunctionAttrs |= 1ULL << I.getKindAsEnum();
+ if (!I.isStringAttribute()) {
+ Attribute::AttrKind Kind = I.getKindAsEnum();
+ AvailableFunctionAttrs[Kind / 8] |= 1ULL << (Kind % 8);
+ }
}
}
From cafb5d24dfa0faf3fa7dfb7eefd7df08aeb01e55 Mon Sep 17 00:00:00 2001
From: Fangrui Song
Date: Sat, 13 Jul 2019 00:47:58 +0000
Subject: [PATCH 018/451] clang/test/Driver/fsanitize.c: Fix -fsanitize=vptr
using default target
The default implementation of getSupportedSanitizers isn't able to turn
on the vptr sanitizer, and thus, any platform that runs this test will
fail with the error:
clang: error: unsupported option '-fsanitize=vptr' for target ''
Patch by James Nagurne!
llvm-svn: 365981
---
clang/test/Driver/fsanitize.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index 187d4bfd4301e..a275b576688e6 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -97,7 +97,7 @@
// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-TRAP-UNDEF
// CHECK-VPTR-TRAP-UNDEF: error: invalid argument '-fsanitize=vptr' not allowed with '-fsanitize-trap=undefined'
-// RUN: %clang -fsanitize=vptr -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
// CHECK-VPTR-NO-RTTI: '-fsanitize=vptr' not allowed with '-fno-rtti'
// RUN: %clang -fsanitize=undefined -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NO-RTTI
From 4f519b6919d2e6e1fb164b87a0d1a5c390581cbe Mon Sep 17 00:00:00 2001
From: Julian Lettner
Date: Sat, 13 Jul 2019 00:55:06 +0000
Subject: [PATCH 019/451] [TSan] Tiny cleanup of UnmangleLongJmpSp for
Linux/x86_64
NFC.
llvm-svn: 365982
---
compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
index 5d9284c525084..0f23da0e877fe 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
@@ -373,9 +373,7 @@ int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {
// Reverse operation of libc stack pointer mangling
static uptr UnmangleLongJmpSp(uptr mangled_sp) {
#if defined(__x86_64__)
-# if SANITIZER_FREEBSD || SANITIZER_NETBSD
- return mangled_sp;
-# else // Linux
+# if SANITIZER_LINUX
// Reverse of:
// xor %fs:0x30, %rsi
// rol $0x11, %rsi
@@ -385,6 +383,8 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) {
: "=r" (sp)
: "0" (mangled_sp));
return sp;
+# else
+ return mangled_sp;
# endif
#elif defined(__aarch64__)
# if SANITIZER_LINUX
@@ -394,11 +394,11 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) {
# endif
#elif defined(__powerpc64__)
// Reverse of:
- // ld r4, -28696(r13)
- // xor r4, r3, r4
- uptr xor_guard;
- asm("ld %0, -28696(%%r13) \n" : "=r" (xor_guard));
- return mangled_sp ^ xor_guard;
+ // ld r4, -28696(r13)
+ // xor r4, r3, r4
+ uptr xor_key;
+ asm("ld %0, -28696(%%r13)" : "=r" (xor_key));
+ return mangled_sp ^ xor_key;
#elif defined(__mips__)
return mangled_sp;
#else
From 0a7f4cdce9fa07f9027181b19db59b5231932487 Mon Sep 17 00:00:00 2001
From: Johannes Doerfert
Date: Sat, 13 Jul 2019 01:09:21 +0000
Subject: [PATCH 020/451] [Attributor] Only return attributes with a valid
state
Attributor::getAAFor will now only return AbstractAttributes with a
valid AbstractState. This simplifies call sites as they only need to
check if the returned pointer is non-null. It also reduces the potential
for accidental misuse.
llvm-svn: 365983
---
llvm/include/llvm/Transforms/IPO/Attributor.h | 8 ++++++--
llvm/lib/Transforms/IPO/Attributor.cpp | 5 ++---
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 0b72394e8e9ec..435aaca75d1c2 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -199,8 +199,12 @@ struct Attributor {
const auto &KindToAbstractAttributeMap = AAMap.lookup({&V, ArgNo});
if (AAType *AA = static_cast(
KindToAbstractAttributeMap.lookup(AAType::ID))) {
- QueryMap[AA].insert(&QueryingAA);
- return AA;
+ // Do not return an attribute with an invalid state. This minimizes checks
+ // at the calls sites and allows the fallback below to kick in.
+ if (AA->getState().isValidState()) {
+ QueryMap[AA].insert(&QueryingAA);
+ return AA;
+ }
}
// If no abstract attribute was found and we look for a call site argument,
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 85aa7a63ada57..5fea3d0b87a09 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -655,7 +655,7 @@ ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) {
// Try to find a assumed unique return value for the called function.
auto *RetCSAA = A.getAAFor(*this, *RV);
- if (!RetCSAA || !RetCSAA->isValidState()) {
+ if (!RetCSAA) {
HasOverdefinedReturnedCalls = true;
LLVM_DEBUG(dbgs() << "[AAReturnedValues] Returned call site (" << *RV
<< ") with " << (RetCSAA ? "invalid" : "no")
@@ -965,8 +965,7 @@ ChangeStatus AANoFreeFunction::updateImpl(Attributor &A) {
auto ICS = ImmutableCallSite(I);
auto *NoFreeAA = A.getAAFor(*this, *I);
- if ((!NoFreeAA || !NoFreeAA->isValidState() ||
- !NoFreeAA->isAssumedNoFree()) &&
+ if ((!NoFreeAA || !NoFreeAA->isAssumedNoFree()) &&
!ICS.hasFnAttr(Attribute::NoFree)) {
indicatePessimisticFixpoint();
return ChangeStatus::CHANGED;
From c7a1db329849b3a5763545a274ed9c91c592553b Mon Sep 17 00:00:00 2001
From: Johannes Doerfert
Date: Sat, 13 Jul 2019 01:09:27 +0000
Subject: [PATCH 021/451] [Attributor][NFC] Run clang-format on the attributor
files (.h/.cpp)
The Attributor files are kept formatted with clang-format, we should try
to keep this state.
llvm-svn: 365984
---
llvm/include/llvm/Transforms/IPO/Attributor.h | 4 +---
llvm/lib/Transforms/IPO/Attributor.cpp | 19 +++++++------------
2 files changed, 8 insertions(+), 15 deletions(-)
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 435aaca75d1c2..88b6af3abbd3d 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -693,9 +693,7 @@ struct AANoSync : public AbstractAttribute {
: AbstractAttribute(V, InfoCache) {}
/// See AbstractAttribute::getAttrKind().
- Attribute::AttrKind getAttrKind() const override {
- return ID;
- }
+ Attribute::AttrKind getAttrKind() const override { return ID; }
static constexpr Attribute::AttrKind ID =
Attribute::AttrKind(Attribute::NoSync);
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 5fea3d0b87a09..5a72865db9d0f 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -359,9 +359,7 @@ struct AANoUnwindFunction : AANoUnwind, BooleanState {
/// }
/// See AbstractAttribute::getManifestPosition().
- ManifestPosition getManifestPosition() const override {
- return MP_FUNCTION;
- }
+ ManifestPosition getManifestPosition() const override { return MP_FUNCTION; }
const std::string getAsStr() const override {
return getAssumed() ? "nounwind" : "may-unwind";
@@ -500,9 +498,7 @@ class AAReturnedValuesImpl final : public AAReturnedValues, AbstractState {
const AbstractState &getState() const override { return *this; }
/// See AbstractAttribute::getManifestPosition().
- ManifestPosition getManifestPosition() const override {
- return MP_ARGUMENT;
- }
+ ManifestPosition getManifestPosition() const override { return MP_ARGUMENT; }
/// See AbstractAttribute::updateImpl(Attributor &A).
ChangeStatus updateImpl(Attributor &A) override;
@@ -742,9 +738,7 @@ struct AANoSyncFunction : AANoSync, BooleanState {
/// }
/// See AbstractAttribute::getManifestPosition().
- ManifestPosition getManifestPosition() const override {
- return MP_FUNCTION;
- }
+ ManifestPosition getManifestPosition() const override { return MP_FUNCTION; }
const std::string getAsStr() const override {
return getAssumed() ? "nosync" : "may-sync";
@@ -767,7 +761,8 @@ struct AANoSyncFunction : AANoSync, BooleanState {
/// Helper function used to determine whether an instruction is volatile.
static bool isVolatile(Instruction *I);
- /// Helper function uset to check if intrinsic is volatile (memcpy, memmove, memset).
+ /// Helper function uset to check if intrinsic is volatile (memcpy, memmove,
+ /// memset).
static bool isNoSyncIntrinsic(Instruction *I);
};
@@ -870,7 +865,7 @@ ChangeStatus AANoSyncFunction::updateImpl(Attributor &A) {
auto *NoSyncAA = A.getAAFor(*this, *I);
if (isa(I) && isNoSyncIntrinsic(I))
- continue;
+ continue;
if (ICS && (!NoSyncAA || !NoSyncAA->isAssumedNoSync()) &&
!ICS.hasFnAttr(Attribute::NoSync)) {
@@ -878,7 +873,7 @@ ChangeStatus AANoSyncFunction::updateImpl(Attributor &A) {
return ChangeStatus::CHANGED;
}
- if(ICS)
+ if (ICS)
continue;
if (!isVolatile(I) && !isNonRelaxedAtomic(I))
From 81b03d4a08b16217669fcccb96e7cc436ab3d74a Mon Sep 17 00:00:00 2001
From: Akira Hatanaka
Date: Sat, 13 Jul 2019 01:47:15 +0000
Subject: [PATCH 022/451] [Sema] Diagnose default-initialization, destruction,
and copying of non-trivial C union types
This patch diagnoses uses of non-trivial C unions and structs/unions
containing non-trivial C unions in the following contexts, which require
default-initialization, destruction, or copying of the union objects,
instead of disallowing fields of non-trivial types in C unions, which is
what we currently do:
- function parameters.
- function returns.
- assignments.
- compound literals.
- block captures except capturing of `__block` variables by non-escaping
blocks.
- local and global variable definitions.
- lvalue-to-rvalue conversions of volatile types.
See the discussion in https://reviews.llvm.org/D62988 for more background.
rdar://problem/50679094
Differential Revision: https://reviews.llvm.org/D63753
llvm-svn: 365985
---
clang/include/clang/AST/Decl.h | 24 ++
clang/include/clang/AST/DeclBase.h | 9 +-
clang/include/clang/AST/Type.h | 45 ++-
.../clang/Basic/DiagnosticSemaKinds.td | 19 +-
clang/include/clang/Sema/Sema.h | 42 +++
clang/lib/AST/Type.cpp | 60 +---
clang/lib/Sema/Sema.cpp | 18 +-
clang/lib/Sema/SemaDecl.cpp | 329 ++++++++++++++++--
clang/lib/Sema/SemaExpr.cpp | 33 +-
clang/lib/Sema/SemaType.cpp | 5 +
clang/lib/Serialization/ASTReaderDecl.cpp | 3 +
clang/lib/Serialization/ASTWriterDecl.cpp | 9 +
.../test/CodeGenObjC/Inputs/strong_in_union.h | 10 -
clang/test/CodeGenObjC/strong-in-c-struct.m | 15 +-
clang/test/PCH/non-trivial-c-union.m | 24 ++
clang/test/SemaObjC/arc-decls.m | 6 +-
clang/test/SemaObjC/non-trivial-c-union.m | 82 +++++
17 files changed, 611 insertions(+), 122 deletions(-)
delete mode 100644 clang/test/CodeGenObjC/Inputs/strong_in_union.h
create mode 100644 clang/test/PCH/non-trivial-c-union.m
create mode 100644 clang/test/SemaObjC/non-trivial-c-union.m
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index e593dafb5fc4d..02742801f37c2 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3746,6 +3746,30 @@ class RecordDecl : public TagDecl {
RecordDeclBits.NonTrivialToPrimitiveDestroy = V;
}
+ bool hasNonTrivialToPrimitiveDefaultInitializeCUnion() const {
+ return RecordDeclBits.HasNonTrivialToPrimitiveDefaultInitializeCUnion;
+ }
+
+ void setHasNonTrivialToPrimitiveDefaultInitializeCUnion(bool V) {
+ RecordDeclBits.HasNonTrivialToPrimitiveDefaultInitializeCUnion = V;
+ }
+
+ bool hasNonTrivialToPrimitiveDestructCUnion() const {
+ return RecordDeclBits.HasNonTrivialToPrimitiveDestructCUnion;
+ }
+
+ void setHasNonTrivialToPrimitiveDestructCUnion(bool V) {
+ RecordDeclBits.HasNonTrivialToPrimitiveDestructCUnion = V;
+ }
+
+ bool hasNonTrivialToPrimitiveCopyCUnion() const {
+ return RecordDeclBits.HasNonTrivialToPrimitiveCopyCUnion;
+ }
+
+ void setHasNonTrivialToPrimitiveCopyCUnion(bool V) {
+ RecordDeclBits.HasNonTrivialToPrimitiveCopyCUnion = V;
+ }
+
/// Determine whether this class can be passed in registers. In C++ mode,
/// it must have at least one trivial, non-deleted copy or move constructor.
/// FIXME: This should be set as part of completeDefinition.
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 26edb7790c261..d64d0cb425db0 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -1440,6 +1440,13 @@ class DeclContext {
uint64_t NonTrivialToPrimitiveCopy : 1;
uint64_t NonTrivialToPrimitiveDestroy : 1;
+ /// The following bits indicate whether this is or contains a C union that
+ /// is non-trivial to default-initialize, destruct, or copy. These bits
+ /// imply the associated basic non-triviality predicates declared above.
+ uint64_t HasNonTrivialToPrimitiveDefaultInitializeCUnion : 1;
+ uint64_t HasNonTrivialToPrimitiveDestructCUnion : 1;
+ uint64_t HasNonTrivialToPrimitiveCopyCUnion : 1;
+
/// Indicates whether this struct is destroyed in the callee.
uint64_t ParamDestroyedInCallee : 1;
@@ -1448,7 +1455,7 @@ class DeclContext {
};
/// Number of non-inherited bits in RecordDeclBitfields.
- enum { NumRecordDeclBits = 11 };
+ enum { NumRecordDeclBits = 14 };
/// Stores the bits used by OMPDeclareReductionDecl.
/// If modified NumOMPDeclareReductionDeclBits and the accessor
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 00a2b7643370a..584655fe789e6 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1129,12 +1129,6 @@ class QualType {
PCK_Struct
};
- /// Check if this is a non-trivial type that would cause a C struct
- /// transitively containing this type to be non-trivial. This function can be
- /// used to determine whether a field of this type can be declared inside a C
- /// union.
- bool isNonTrivialPrimitiveCType(const ASTContext &Ctx) const;
-
/// Check if this is a non-trivial type that would cause a C struct
/// transitively containing this type to be non-trivial to copy and return the
/// kind.
@@ -1164,6 +1158,22 @@ class QualType {
return isDestructedTypeImpl(*this);
}
+ /// Check if this is or contains a C union that is non-trivial to
+ /// default-initialize, which is a union that has a member that is non-trivial
+ /// to default-initialize. If this returns true,
+ /// isNonTrivialToPrimitiveDefaultInitialize returns PDIK_Struct.
+ bool hasNonTrivialToPrimitiveDefaultInitializeCUnion() const;
+
+ /// Check if this is or contains a C union that is non-trivial to destruct,
+ /// which is a union that has a member that is non-trivial to destruct. If
+ /// this returns true, isDestructedType returns DK_nontrivial_c_struct.
+ bool hasNonTrivialToPrimitiveDestructCUnion() const;
+
+ /// Check if this is or contains a C union that is non-trivial to copy, which
+ /// is a union that has a member that is non-trivial to copy. If this returns
+ /// true, isNonTrivialToPrimitiveCopy returns PCK_Struct.
+ bool hasNonTrivialToPrimitiveCopyCUnion() const;
+
/// Determine whether expressions of the given type are forbidden
/// from being lvalues in C.
///
@@ -1236,6 +1246,11 @@ class QualType {
const ASTContext &C);
static QualType IgnoreParens(QualType T);
static DestructionKind isDestructedTypeImpl(QualType type);
+
+ /// Check if \param RD is or contains a non-trivial C union.
+ static bool hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD);
+ static bool hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD);
+ static bool hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD);
};
} // namespace clang
@@ -6249,6 +6264,24 @@ inline Qualifiers::GC QualType::getObjCGCAttr() const {
return getQualifiers().getObjCGCAttr();
}
+inline bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion() const {
+ if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl())
+ return hasNonTrivialToPrimitiveDefaultInitializeCUnion(RD);
+ return false;
+}
+
+inline bool QualType::hasNonTrivialToPrimitiveDestructCUnion() const {
+ if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl())
+ return hasNonTrivialToPrimitiveDestructCUnion(RD);
+ return false;
+}
+
+inline bool QualType::hasNonTrivialToPrimitiveCopyCUnion() const {
+ if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl())
+ return hasNonTrivialToPrimitiveCopyCUnion(RD);
+ return false;
+}
+
inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) {
if (const auto *PT = t.getAs()) {
if (const auto *FT = PT->getPointeeType()->getAs())
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 380db32ba4bf5..c68271b784da1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -620,8 +620,23 @@ def warn_cstruct_memaccess : Warning<
InGroup;
def note_nontrivial_field : Note<
"field is non-trivial to %select{copy|default-initialize}0">;
-def err_nontrivial_primitive_type_in_union : Error<
- "non-trivial C types are disallowed in union">;
+def err_non_trivial_c_union_in_invalid_context : Error<
+ "cannot %select{"
+ "use type %1 for a function/method parameter|"
+ "use type %1 for function/method return|"
+ "default-initialize an object of type %1|"
+ "declare an automatic variable of type %1|"
+ "copy-initialize an object of type %1|"
+ "assign to a variable of type %1|"
+ "construct an automatic compound literal of type %1|"
+ "capture a variable of type %1|"
+ "cannot use volatile type %1 where it causes an lvalue-to-rvalue conversion"
+ "}3 "
+ "since it %select{contains|is}2 a union that is non-trivial to "
+ "%select{default-initialize|destruct|copy}0">;
+def note_non_trivial_c_union : Note<
+ "%select{%2 has subobjects that are|%3 has type %2 that is}0 "
+ "non-trivial to %select{default-initialize|destruct|copy}1">;
def warn_dyn_class_memaccess : Warning<
"%select{destination for|source of|first operand of|second operand of}0 this "
"%1 call is a pointer to %select{|class containing a }2dynamic class %3; "
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 8f66cda46b65c..af762f74d745c 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2114,6 +2114,48 @@ class Sema {
bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg,
SourceLocation EqualLoc);
+ // Contexts where using non-trivial C union types can be disallowed. This is
+ // passed to err_non_trivial_c_union_in_invalid_context.
+ enum NonTrivialCUnionContext {
+ // Function parameter.
+ NTCUC_FunctionParam,
+ // Function return.
+ NTCUC_FunctionReturn,
+ // Default-initialized object.
+ NTCUC_DefaultInitializedObject,
+ // Variable with automatic storage duration.
+ NTCUC_AutoVar,
+ // Initializer expression that might copy from another object.
+ NTCUC_CopyInit,
+ // Assignment.
+ NTCUC_Assignment,
+ // Compound literal.
+ NTCUC_CompoundLiteral,
+ // Block capture.
+ NTCUC_BlockCapture,
+ // lvalue-to-rvalue conversion of volatile type.
+ NTCUC_LValueToRValueVolatile,
+ };
+
+ /// Emit diagnostics if the initializer or any of its explicit or
+ /// implicitly-generated subexpressions require copying or
+ /// default-initializing a type that is or contains a C union type that is
+ /// non-trivial to copy or default-initialize.
+ void checkNonTrivialCUnionInInitializer(const Expr *Init, SourceLocation Loc);
+
+ // These flags are passed to checkNonTrivialCUnion.
+ enum NonTrivialCUnionKind {
+ NTCUK_Init = 0x1,
+ NTCUK_Destruct = 0x2,
+ NTCUK_Copy = 0x4,
+ };
+
+ /// Emit diagnostics if a non-trivial C union type or a struct that contains
+ /// a non-trivial C union is used in an invalid context.
+ void checkNonTrivialCUnion(QualType QT, SourceLocation Loc,
+ NonTrivialCUnionContext UseContext,
+ unsigned NonTrivialKind);
+
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit);
void ActOnUninitializedDecl(Decl *dcl);
void ActOnInitializerError(Decl *Dcl);
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 733ca232dd037..01e93c11aad87 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2276,60 +2276,16 @@ bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const {
getObjCLifetime() != Qualifiers::OCL_Weak;
}
-namespace {
-// Helper class that determines whether this is a type that is non-trivial to
-// primitive copy or move, or is a struct type that has a field of such type.
-template
-struct IsNonTrivialCopyMoveVisitor
- : CopiedTypeVisitor, IsMove, bool> {
- using Super =
- CopiedTypeVisitor, IsMove, bool>;
- IsNonTrivialCopyMoveVisitor(const ASTContext &C) : Ctx(C) {}
- void preVisit(QualType::PrimitiveCopyKind PCK, QualType QT) {}
-
- bool visitWithKind(QualType::PrimitiveCopyKind PCK, QualType QT) {
- if (const auto *AT = this->Ctx.getAsArrayType(QT))
- return this->asDerived().visit(Ctx.getBaseElementType(AT));
- return Super::visitWithKind(PCK, QT);
- }
-
- bool visitARCStrong(QualType QT) { return true; }
- bool visitARCWeak(QualType QT) { return true; }
- bool visitTrivial(QualType QT) { return false; }
- // Volatile fields are considered trivial.
- bool visitVolatileTrivial(QualType QT) { return false; }
-
- bool visitStruct(QualType QT) {
- const RecordDecl *RD = QT->castAs()->getDecl();
- // We don't want to apply the C restriction in C++ because C++
- // (1) can apply the restriction at a finer grain by banning copying or
- // destroying the union, and
- // (2) allows users to override these restrictions by declaring explicit
- // constructors/etc, which we're not proposing to add to C.
- if (isa(RD))
- return false;
- for (const FieldDecl *FD : RD->fields())
- if (this->asDerived().visit(FD->getType()))
- return true;
- return false;
- }
-
- const ASTContext &Ctx;
-};
+bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD) {
+ return RD->hasNonTrivialToPrimitiveDefaultInitializeCUnion();
+}
-} // namespace
+bool QualType::hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD) {
+ return RD->hasNonTrivialToPrimitiveDestructCUnion();
+}
-bool QualType::isNonTrivialPrimitiveCType(const ASTContext &Ctx) const {
- if (isNonTrivialToPrimitiveDefaultInitialize())
- return true;
- DestructionKind DK = isDestructedType();
- if (DK != DK_none && DK != DK_cxx_destructor)
- return true;
- if (IsNonTrivialCopyMoveVisitor(Ctx).visit(*this))
- return true;
- if (IsNonTrivialCopyMoveVisitor(Ctx).visit(*this))
- return true;
- return false;
+bool QualType::hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD) {
+ return RD->hasNonTrivialToPrimitiveCopyCUnion();
}
QualType::PrimitiveDefaultInitializeKind
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 3941643893af6..11fed28b52db0 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1658,12 +1658,24 @@ static void markEscapingByrefs(const FunctionScopeInfo &FSI, Sema &S) {
// Set the EscapingByref flag of __block variables captured by
// escaping blocks.
for (const BlockDecl *BD : FSI.Blocks) {
- if (BD->doesNotEscape())
- continue;
for (const BlockDecl::Capture &BC : BD->captures()) {
VarDecl *VD = BC.getVariable();
- if (VD->hasAttr())
+ if (VD->hasAttr()) {
+ // Nothing to do if this is a __block variable captured by a
+ // non-escaping block.
+ if (BD->doesNotEscape())
+ continue;
VD->setEscapingByref();
+ }
+ // Check whether the captured variable is or contains an object of
+ // non-trivial C union type.
+ QualType CapType = BC.getVariable()->getType();
+ if (CapType.hasNonTrivialToPrimitiveDestructCUnion() ||
+ CapType.hasNonTrivialToPrimitiveCopyCUnion())
+ S.checkNonTrivialCUnion(BC.getVariable()->getType(),
+ BD->getCaretLocation(),
+ Sema::NTCUC_BlockCapture,
+ Sema::NTCUK_Destruct|Sema::NTCUK_Copy);
}
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index b2a0632c6e7f1..73407afb49f34 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/NonTrivialTypeVisitor.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -6504,6 +6505,11 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (D.isInvalidType())
NewVD->setInvalidDecl();
+
+ if (NewVD->getType().hasNonTrivialToPrimitiveDestructCUnion() &&
+ NewVD->hasLocalStorage())
+ checkNonTrivialCUnion(NewVD->getType(), NewVD->getLocation(),
+ NTCUC_AutoVar, NTCUK_Destruct);
} else {
bool Invalid = false;
@@ -8924,6 +8930,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< FunctionType::getNameForCallConv(CC);
}
}
+
+ if (NewFD->getReturnType().hasNonTrivialToPrimitiveDestructCUnion() ||
+ NewFD->getReturnType().hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(NewFD->getReturnType(),
+ NewFD->getReturnTypeSourceRange().getBegin(),
+ NTCUC_FunctionReturn, NTCUK_Destruct|NTCUK_Copy);
} else {
// C++11 [replacement.functions]p3:
// The program's definitions shall not be specified as inline.
@@ -11070,6 +11082,263 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
return VDecl->isInvalidDecl();
}
+void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init, SourceLocation Loc) {
+ if (auto *CE = dyn_cast(Init))
+ Init = CE->getSubExpr();
+
+ QualType InitType = Init->getType();
+ assert((InitType.hasNonTrivialToPrimitiveDefaultInitializeCUnion() ||
+ InitType.hasNonTrivialToPrimitiveCopyCUnion()) &&
+ "shouldn't be called if type doesn't have a non-trivial C struct");
+ if (auto *ILE = dyn_cast(Init)) {
+ for (auto I : ILE->inits()) {
+ if (!I->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() &&
+ !I->getType().hasNonTrivialToPrimitiveCopyCUnion())
+ continue;
+ SourceLocation SL = I->getExprLoc();
+ checkNonTrivialCUnionInInitializer(I, SL.isValid() ? SL : Loc);
+ }
+ return;
+ }
+
+ if (isa(Init)) {
+ if (InitType.hasNonTrivialToPrimitiveDefaultInitializeCUnion())
+ checkNonTrivialCUnion(InitType, Loc, NTCUC_DefaultInitializedObject,
+ NTCUK_Init);
+ } else {
+ // Assume all other explicit initializers involving copying some existing
+ // object.
+ // TODO: ignore any explicit initializers where we can guarantee
+ // copy-elision.
+ if (InitType.hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(InitType, Loc, NTCUC_CopyInit, NTCUK_Copy);
+ }
+};
+
+namespace {
+
+struct DiagNonTrivalCUnionDefaultInitializeVisitor
+ : DefaultInitializedTypeVisitor {
+ using Super =
+ DefaultInitializedTypeVisitor;
+
+ DiagNonTrivalCUnionDefaultInitializeVisitor(
+ QualType OrigTy, SourceLocation OrigLoc,
+ Sema::NonTrivialCUnionContext UseContext, Sema &S)
+ : OrigTy(OrigTy), OrigLoc(OrigLoc), UseContext(UseContext), S(S) {}
+
+ void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType QT,
+ const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (const auto *AT = S.Context.getAsArrayType(QT))
+ return this->asDerived().visit(S.Context.getBaseElementType(AT), FD,
+ InNonTrivialUnion);
+ return Super::visitWithKind(PDIK, QT, FD, InNonTrivialUnion);
+ }
+
+ void visitARCStrong(QualType QT, const FieldDecl *FD,
+ bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 0 << QT << FD->getName();
+ }
+
+ void visitARCWeak(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 0 << QT << FD->getName();
+ }
+
+ void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ const RecordDecl *RD = QT->castAs()->getDecl();
+ if (RD->isUnion()) {
+ if (OrigLoc.isValid()) {
+ bool IsUnion = false;
+ if (auto *OrigRD = OrigTy->getAsRecordDecl())
+ IsUnion = OrigRD->isUnion();
+ S.Diag(OrigLoc, diag::err_non_trivial_c_union_in_invalid_context)
+ << 0 << OrigTy << IsUnion << UseContext;
+ // Reset OrigLoc so that this diagnostic is emitted only once.
+ OrigLoc = SourceLocation();
+ }
+ InNonTrivialUnion = true;
+ }
+
+ if (InNonTrivialUnion)
+ S.Diag(RD->getLocation(), diag::note_non_trivial_c_union)
+ << 0 << 0 << QT.getUnqualifiedType() << "";
+
+ for (const FieldDecl *FD : RD->fields())
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ }
+
+ void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}
+
+ // The non-trivial C union type or the struct/union type that contains a
+ // non-trivial C union.
+ QualType OrigTy;
+ SourceLocation OrigLoc;
+ Sema::NonTrivialCUnionContext UseContext;
+ Sema &S;
+};
+
+struct DiagNonTrivalCUnionDestructedTypeVisitor
+ : DestructedTypeVisitor {
+ using Super =
+ DestructedTypeVisitor;
+
+ DiagNonTrivalCUnionDestructedTypeVisitor(
+ QualType OrigTy, SourceLocation OrigLoc,
+ Sema::NonTrivialCUnionContext UseContext, Sema &S)
+ : OrigTy(OrigTy), OrigLoc(OrigLoc), UseContext(UseContext), S(S) {}
+
+ void visitWithKind(QualType::DestructionKind DK, QualType QT,
+ const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (const auto *AT = S.Context.getAsArrayType(QT))
+ return this->asDerived().visit(S.Context.getBaseElementType(AT), FD,
+ InNonTrivialUnion);
+ return Super::visitWithKind(DK, QT, FD, InNonTrivialUnion);
+ }
+
+ void visitARCStrong(QualType QT, const FieldDecl *FD,
+ bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 1 << QT << FD->getName();
+ }
+
+ void visitARCWeak(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 1 << QT << FD->getName();
+ }
+
+ void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ const RecordDecl *RD = QT->castAs()->getDecl();
+ if (RD->isUnion()) {
+ if (OrigLoc.isValid()) {
+ bool IsUnion = false;
+ if (auto *OrigRD = OrigTy->getAsRecordDecl())
+ IsUnion = OrigRD->isUnion();
+ S.Diag(OrigLoc, diag::err_non_trivial_c_union_in_invalid_context)
+ << 1 << OrigTy << IsUnion << UseContext;
+ // Reset OrigLoc so that this diagnostic is emitted only once.
+ OrigLoc = SourceLocation();
+ }
+ InNonTrivialUnion = true;
+ }
+
+ if (InNonTrivialUnion)
+ S.Diag(RD->getLocation(), diag::note_non_trivial_c_union)
+ << 0 << 1 << QT.getUnqualifiedType() << "";
+
+ for (const FieldDecl *FD : RD->fields())
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ }
+
+ void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}
+ void visitCXXDestructor(QualType QT, const FieldDecl *FD,
+ bool InNonTrivialUnion) {}
+
+ // The non-trivial C union type or the struct/union type that contains a
+ // non-trivial C union.
+ QualType OrigTy;
+ SourceLocation OrigLoc;
+ Sema::NonTrivialCUnionContext UseContext;
+ Sema &S;
+};
+
+struct DiagNonTrivalCUnionCopyVisitor
+ : CopiedTypeVisitor {
+ using Super = CopiedTypeVisitor;
+
+ DiagNonTrivalCUnionCopyVisitor(QualType OrigTy, SourceLocation OrigLoc,
+ Sema::NonTrivialCUnionContext UseContext,
+ Sema &S)
+ : OrigTy(OrigTy), OrigLoc(OrigLoc), UseContext(UseContext), S(S) {}
+
+ void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType QT,
+ const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (const auto *AT = S.Context.getAsArrayType(QT))
+ return this->asDerived().visit(S.Context.getBaseElementType(AT), FD,
+ InNonTrivialUnion);
+ return Super::visitWithKind(PCK, QT, FD, InNonTrivialUnion);
+ }
+
+ void visitARCStrong(QualType QT, const FieldDecl *FD,
+ bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 2 << QT << FD->getName();
+ }
+
+ void visitARCWeak(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ if (InNonTrivialUnion)
+ S.Diag(FD->getLocation(), diag::note_non_trivial_c_union)
+ << 1 << 2 << QT << FD->getName();
+ }
+
+ void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {
+ const RecordDecl *RD = QT->castAs()->getDecl();
+ if (RD->isUnion()) {
+ if (OrigLoc.isValid()) {
+ bool IsUnion = false;
+ if (auto *OrigRD = OrigTy->getAsRecordDecl())
+ IsUnion = OrigRD->isUnion();
+ S.Diag(OrigLoc, diag::err_non_trivial_c_union_in_invalid_context)
+ << 2 << OrigTy << IsUnion << UseContext;
+ // Reset OrigLoc so that this diagnostic is emitted only once.
+ OrigLoc = SourceLocation();
+ }
+ InNonTrivialUnion = true;
+ }
+
+ if (InNonTrivialUnion)
+ S.Diag(RD->getLocation(), diag::note_non_trivial_c_union)
+ << 0 << 2 << QT.getUnqualifiedType() << "";
+
+ for (const FieldDecl *FD : RD->fields())
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ }
+
+ void preVisit(QualType::PrimitiveCopyKind PCK, QualType QT,
+ const FieldDecl *FD, bool InNonTrivialUnion) {}
+ void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}
+ void visitVolatileTrivial(QualType QT, const FieldDecl *FD,
+ bool InNonTrivialUnion) {}
+
+ // The non-trivial C union type or the struct/union type that contains a
+ // non-trivial C union.
+ QualType OrigTy;
+ SourceLocation OrigLoc;
+ Sema::NonTrivialCUnionContext UseContext;
+ Sema &S;
+};
+
+} // namespace
+
+void Sema::checkNonTrivialCUnion(QualType QT, SourceLocation Loc,
+ NonTrivialCUnionContext UseContext,
+ unsigned NonTrivialKind) {
+ assert((QT.hasNonTrivialToPrimitiveDefaultInitializeCUnion() ||
+ QT.hasNonTrivialToPrimitiveDestructCUnion() ||
+ QT.hasNonTrivialToPrimitiveCopyCUnion()) &&
+ "shouldn't be called if type doesn't have a non-trivial C union");
+
+ if ((NonTrivialKind & NTCUK_Init) &&
+ QT.hasNonTrivialToPrimitiveDefaultInitializeCUnion())
+ DiagNonTrivalCUnionDefaultInitializeVisitor(QT, Loc, UseContext, *this)
+ .visit(QT, nullptr, false);
+ if ((NonTrivialKind & NTCUK_Destruct) &&
+ QT.hasNonTrivialToPrimitiveDestructCUnion())
+ DiagNonTrivalCUnionDestructedTypeVisitor(QT, Loc, UseContext, *this)
+ .visit(QT, nullptr, false);
+ if ((NonTrivialKind & NTCUK_Copy) && QT.hasNonTrivialToPrimitiveCopyCUnion())
+ DiagNonTrivalCUnionCopyVisitor(QT, Loc, UseContext, *this)
+ .visit(QT, nullptr, false);
+}
+
/// AddInitializerToDecl - Adds the initializer Init to the
/// declaration dcl. If DirectInit is true, this is C++ direct
/// initialization rather than copy initialization.
@@ -11475,6 +11744,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
CheckForConstantInitializer(Init, DclT);
}
+ QualType InitType = Init->getType();
+ if (!InitType.isNull() &&
+ (InitType.hasNonTrivialToPrimitiveDefaultInitializeCUnion() ||
+ InitType.hasNonTrivialToPrimitiveCopyCUnion()))
+ checkNonTrivialCUnionInInitializer(Init, Init->getExprLoc());
+
// We will represent direct-initialization similarly to copy-initialization:
// int x(1); -as-> int x = 1;
// ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c);
@@ -11599,7 +11874,14 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
return;
}
- switch (Var->isThisDeclarationADefinition()) {
+ VarDecl::DefinitionKind DefKind = Var->isThisDeclarationADefinition();
+ if (!Var->isInvalidDecl() && DefKind != VarDecl::DeclarationOnly &&
+ Var->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion())
+ checkNonTrivialCUnion(Var->getType(), Var->getLocation(),
+ NTCUC_DefaultInitializedObject, NTCUK_Init);
+
+
+ switch (DefKind) {
case VarDecl::Definition:
if (!Var->isStaticDataMember() || !Var->getAnyInitializer())
break;
@@ -12692,6 +12974,11 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
Context.getAdjustedParameterType(T),
TSInfo, SC, nullptr);
+ if (New->getType().hasNonTrivialToPrimitiveDestructCUnion() ||
+ New->getType().hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(New->getType(), New->getLocation(),
+ NTCUC_FunctionParam, NTCUK_Destruct|NTCUK_Copy);
+
// Parameters can not be abstract class types.
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
@@ -15938,7 +16225,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// Verify that all the fields are okay.
SmallVector RecFields;
- bool ObjCFieldLifetimeErrReported = false;
for (ArrayRef::iterator i = Fields.begin(), end = Fields.end();
i != end; ++i) {
FieldDecl *FD = cast(*i);
@@ -16077,38 +16363,12 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
Record->setHasObjectMember(true);
if (Record && FDTTy->getDecl()->hasVolatileMember())
Record->setHasVolatileMember(true);
- if (Record && Record->isUnion() &&
- FD->getType().isNonTrivialPrimitiveCType(Context))
- Diag(FD->getLocation(),
- diag::err_nontrivial_primitive_type_in_union);
} else if (FDTy->isObjCObjectType()) {
/// A field cannot be an Objective-c object
Diag(FD->getLocation(), diag::err_statically_allocated_object)
<< FixItHint::CreateInsertion(FD->getLocation(), "*");
QualType T = Context.getObjCObjectPointerType(FD->getType());
FD->setType(T);
- } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
- Record && !ObjCFieldLifetimeErrReported && Record->isUnion() &&
- !getLangOpts().CPlusPlus) {
- // It's an error in ARC or Weak if a field has lifetime.
- // We don't want to report this in a system header, though,
- // so we just make the field unavailable.
- // FIXME: that's really not sufficient; we need to make the type
- // itself invalid to, say, initialize or copy.
- QualType T = FD->getType();
- if (T.hasNonTrivialObjCLifetime()) {
- SourceLocation loc = FD->getLocation();
- if (getSourceManager().isInSystemHeader(loc)) {
- if (!FD->hasAttr()) {
- FD->addAttr(UnavailableAttr::CreateImplicit(Context, "",
- UnavailableAttr::IR_ARCFieldWithOwnership, loc));
- }
- } else {
- Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag)
- << T->isBlockPointerType() << Record->getTagKind();
- }
- ObjCFieldLifetimeErrReported = true;
- }
} else if (getLangOpts().ObjC &&
getLangOpts().getGC() != LangOptions::NonGC &&
Record && !Record->hasObjectMember()) {
@@ -16128,14 +16388,23 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
if (Record && !getLangOpts().CPlusPlus && !FD->hasAttr()) {
QualType FT = FD->getType();
- if (FT.isNonTrivialToPrimitiveDefaultInitialize())
+ if (FT.isNonTrivialToPrimitiveDefaultInitialize()) {
Record->setNonTrivialToPrimitiveDefaultInitialize(true);
+ if (FT.hasNonTrivialToPrimitiveDefaultInitializeCUnion() ||
+ Record->isUnion())
+ Record->setHasNonTrivialToPrimitiveDefaultInitializeCUnion(true);
+ }
QualType::PrimitiveCopyKind PCK = FT.isNonTrivialToPrimitiveCopy();
- if (PCK != QualType::PCK_Trivial && PCK != QualType::PCK_VolatileTrivial)
+ if (PCK != QualType::PCK_Trivial && PCK != QualType::PCK_VolatileTrivial) {
Record->setNonTrivialToPrimitiveCopy(true);
+ if (FT.hasNonTrivialToPrimitiveCopyCUnion() || Record->isUnion())
+ Record->setHasNonTrivialToPrimitiveCopyCUnion(true);
+ }
if (FT.isDestructedType()) {
Record->setNonTrivialToPrimitiveDestroy(true);
Record->setParamDestroyedInCallee(true);
+ if (FT.hasNonTrivialToPrimitiveDestructCUnion() || Record->isUnion())
+ Record->setHasNonTrivialToPrimitiveDestructCUnion(true);
}
if (const auto *RT = FT->getAs()) {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 746d3e7e11901..1e49a363ab330 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6066,7 +6066,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
ILE->setInit(i, ConstantExpr::Create(Context, Init));
}
- Expr *E = new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
+ auto *E = new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
VK, LiteralExpr, isFileScope);
if (isFileScope) {
if (!LiteralExpr->isTypeDependent() &&
@@ -6084,6 +6084,19 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
return ExprError();
}
+ // Compound literals that have automatic storage duration are destroyed at
+ // the end of the scope. Emit diagnostics if it is or contains a C union type
+ // that is non-trivial to destruct.
+ if (!isFileScope)
+ if (E->getType().hasNonTrivialToPrimitiveDestructCUnion())
+ checkNonTrivialCUnion(E->getType(), E->getExprLoc(),
+ NTCUC_CompoundLiteral, NTCUK_Destruct);
+
+ if (E->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() ||
+ E->getType().hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnionInInitializer(E->getInitializer(),
+ E->getInitializer()->getExprLoc());
+
return MaybeBindToTemporary(E);
}
@@ -12533,6 +12546,10 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (auto *VD = dyn_cast(DRE->getDecl()))
if (VD->hasLocalStorage() && getCurScope()->isDeclScope(VD))
BE->getBlockDecl()->setCanAvoidCopyToHeap();
+
+ if (LHS.get()->getType().hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(LHS.get()->getType(), LHS.get()->getExprLoc(),
+ NTCUC_Assignment, NTCUK_Copy);
}
RecordModifiableNonNullParam(*this, LHS.get());
break;
@@ -13945,6 +13962,11 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
!BD->isDependentContext())
computeNRVO(Body, BSI);
+ if (RetTy.hasNonTrivialToPrimitiveDestructCUnion() ||
+ RetTy.hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(RetTy, BD->getCaretLocation(), NTCUC_FunctionReturn,
+ NTCUK_Destruct|NTCUK_Copy);
+
PopDeclContext();
// Pop the block scope now but keep it alive to the end of this function.
@@ -16196,6 +16218,15 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
}
ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) {
+ // Check whether the operand is or contains an object of non-trivial C union
+ // type.
+ if (E->getType().isVolatileQualified() &&
+ (E->getType().hasNonTrivialToPrimitiveDestructCUnion() ||
+ E->getType().hasNonTrivialToPrimitiveCopyCUnion()))
+ checkNonTrivialCUnion(E->getType(), E->getExprLoc(),
+ Sema::NTCUC_LValueToRValueVolatile,
+ NTCUK_Destruct|NTCUK_Copy);
+
// C++2a [basic.def.odr]p4:
// [...] an expression of non-volatile-qualified non-class type to which
// the lvalue-to-rvalue conversion is applied [...]
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 88b544068a802..514cbd90d3b85 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2456,6 +2456,11 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
return true;
}
+ if (T.hasNonTrivialToPrimitiveDestructCUnion() ||
+ T.hasNonTrivialToPrimitiveCopyCUnion())
+ checkNonTrivialCUnion(T, Loc, NTCUC_FunctionReturn,
+ NTCUK_Destruct|NTCUK_Copy);
+
return false;
}
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index b40e3cf892650..3cac82ad421c0 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -794,6 +794,9 @@ ASTDeclReader::VisitRecordDeclImpl(RecordDecl *RD) {
RD->setNonTrivialToPrimitiveDefaultInitialize(Record.readInt());
RD->setNonTrivialToPrimitiveCopy(Record.readInt());
RD->setNonTrivialToPrimitiveDestroy(Record.readInt());
+ RD->setHasNonTrivialToPrimitiveDefaultInitializeCUnion(Record.readInt());
+ RD->setHasNonTrivialToPrimitiveDestructCUnion(Record.readInt());
+ RD->setHasNonTrivialToPrimitiveCopyCUnion(Record.readInt());
RD->setParamDestroyedInCallee(Record.readInt());
RD->setArgPassingRestrictions((RecordDecl::ArgPassingKind)Record.readInt());
return Redecl;
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 3d9dd7131b1de..b71315505de90 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -476,6 +476,9 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
Record.push_back(D->isNonTrivialToPrimitiveDefaultInitialize());
Record.push_back(D->isNonTrivialToPrimitiveCopy());
Record.push_back(D->isNonTrivialToPrimitiveDestroy());
+ Record.push_back(D->hasNonTrivialToPrimitiveDefaultInitializeCUnion());
+ Record.push_back(D->hasNonTrivialToPrimitiveDestructCUnion());
+ Record.push_back(D->hasNonTrivialToPrimitiveCopyCUnion());
Record.push_back(D->isParamDestroyedInCallee());
Record.push_back(D->getArgPassingRestrictions());
@@ -1999,6 +2002,12 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
// isNonTrivialToPrimitiveDestroy
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
+ // hasNonTrivialToPrimitiveDefaultInitializeCUnion
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
+ // hasNonTrivialToPrimitiveDestructCUnion
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
+ // hasNonTrivialToPrimitiveCopyCUnion
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
// isParamDestroyedInCallee
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
// getArgPassingRestrictions
diff --git a/clang/test/CodeGenObjC/Inputs/strong_in_union.h b/clang/test/CodeGenObjC/Inputs/strong_in_union.h
deleted file mode 100644
index abe4549055c60..0000000000000
--- a/clang/test/CodeGenObjC/Inputs/strong_in_union.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef STRONG_IN_UNION_H
-#define STRONG_IN_UNION_H
-#pragma clang system_header
-
-typedef union {
- id f0;
- int *f1;
-} U;
-
-#endif // STRONG_IN_UNION_H
diff --git a/clang/test/CodeGenObjC/strong-in-c-struct.m b/clang/test/CodeGenObjC/strong-in-c-struct.m
index 19cc1037c4cad..8eeee4af0d30a 100644
--- a/clang/test/CodeGenObjC/strong-in-c-struct.m
+++ b/clang/test/CodeGenObjC/strong-in-c-struct.m
@@ -1,11 +1,10 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-llvm -o - -DUSESTRUCT -I %S/Inputs %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-llvm -o - -DUSESTRUCT %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-pch -I %S/Inputs -o %t %s
-// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -include-pch %t -emit-llvm -o - -DUSESTRUCT -I %S/Inputs %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-pch -o %t %s
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -include-pch %t -emit-llvm -o - -DUSESTRUCT %s | FileCheck %s
#ifndef HEADER
#define HEADER
-#include "strong_in_union.h"
typedef void (^BlockTy)(void);
@@ -695,14 +694,6 @@ void test_copy_constructor_Bitfield1(Bitfield1 *a) {
Bitfield1 t = *a;
}
-// CHECK: define void @test_strong_in_union()
-// CHECK: alloca %{{.*}}
-// CHECK-NEXT: ret void
-
-void test_strong_in_union() {
- U t;
-}
-
// CHECK: define void @test_copy_constructor_VolatileArray(
// CHECK: call void @__copy_constructor_8_8_s0_AB8s4n16_tv64w32_AE(
diff --git a/clang/test/PCH/non-trivial-c-union.m b/clang/test/PCH/non-trivial-c-union.m
new file mode 100644
index 0000000000000..abd335497db26
--- /dev/null
+++ b/clang/test/PCH/non-trivial-c-union.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -emit-pch -o %t.pch %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -include-pch %t.pch -verify %s
+
+#ifndef HEADER
+#define HEADER
+
+typedef union {
+ id f0;
+} U0;
+
+#else
+
+// expected-note@-6 {{'U0' has subobjects that are non-trivial to destruct}}
+// expected-note@-7 {{'U0' has subobjects that are non-trivial to copy}}
+// expected-note@-8 {{'U0' has subobjects that are non-trivial to default-initialize}}
+// expected-note@-8 {{f0 has type '__strong id' that is non-trivial to destruct}}
+// expected-note@-9 {{f0 has type '__strong id' that is non-trivial to copy}}
+// expected-note@-10 {{f0 has type '__strong id' that is non-trivial to default-initialize}}
+
+U0 foo0(void); // expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to copy}}
+
+U0 g0; // expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}}
+
+#endif
diff --git a/clang/test/SemaObjC/arc-decls.m b/clang/test/SemaObjC/arc-decls.m
index 0abd45dac33e2..28c3de996996d 100644
--- a/clang/test/SemaObjC/arc-decls.m
+++ b/clang/test/SemaObjC/arc-decls.m
@@ -8,11 +8,7 @@
};
union u {
- id u; // expected-error {{ARC forbids Objective-C objects in union}}
-};
-
-union u_nontrivial_c {
- struct A a; // expected-error {{non-trivial C types are disallowed in union}}
+ id u;
};
// Volatile fields are fine.
diff --git a/clang/test/SemaObjC/non-trivial-c-union.m b/clang/test/SemaObjC/non-trivial-c-union.m
new file mode 100644
index 0000000000000..7bd82775451c8
--- /dev/null
+++ b/clang/test/SemaObjC/non-trivial-c-union.m
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -fobjc-arc -fobjc-runtime-has-weak -verify %s
+
+typedef union { // expected-note 12 {{'U0' has subobjects that are non-trivial to default-initialize}} expected-note 36 {{'U0' has subobjects that are non-trivial to destruct}} expected-note 28 {{'U0' has subobjects that are non-trivial to copy}}
+ id f0; // expected-note 12 {{f0 has type '__strong id' that is non-trivial to default-initialize}} expected-note 36 {{f0 has type '__strong id' that is non-trivial to destruct}} expected-note 28 {{f0 has type '__strong id' that is non-trivial to copy}}
+ __weak id f1; // expected-note 12 {{f1 has type '__weak id' that is non-trivial to default-initialize}} expected-note 36 {{f1 has type '__weak id' that is non-trivial to destruct}} expected-note 28 {{f1 has type '__weak id' that is non-trivial to copy}}
+} U0;
+
+typedef struct {
+ U0 f0;
+ id f1;
+} S0;
+
+id g0;
+U0 ug0; // expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}}
+U0 ug1 = { .f0 = 0 };
+S0 sg0; // expected-error {{cannot default-initialize an object of type 'S0' since it contains a union that is non-trivial to default-initialize}}
+S0 sg1 = { .f0 = {0}, .f1 = 0 };
+S0 sg2 = { .f1 = 0 }; // expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}}
+
+U0 foo0(U0); // expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to copy}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to copy}}
+S0 foo1(S0); // expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to copy}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to copy}}
+
+@interface C
+-(U0)m0:(U0)arg; // expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to copy}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to copy}}
+-(S0)m1:(S0)arg; // expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to copy}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to copy}}
+@end
+
+void testBlockFunction(void) {
+ (void)^(U0 a){ return ug0; }; // expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to copy}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to copy}}
+ (void)^(S0 a){ return sg0; }; // expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to copy}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to copy}}
+}
+void testAutoVar(void) {
+ U0 u0; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}}
+ U0 u1 = ug0; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot copy-initialize an object of type 'U0' since it is a union that is non-trivial to copy}}
+ U0 u2 = { g0 }; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}}
+ U0 u3 = { .f1 = g0 }; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}}
+ S0 s0; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'S0' since it contains a union that is non-trivial to default-initialize}}
+ S0 s1 = sg0; // expected-error {{declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot copy-initialize an object of type 'S0' since it contains a union that is non-trivial to copy}}
+ S0 s2 = { ug0 }; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot copy-initialize an object of type 'U0' since it is a union that is non-trivial to copy}}
+ S0 s3 = { .f0 = ug0 }; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot copy-initialize an object of type 'U0' since it is a union that is non-trivial to copy}}
+ S0 s4 = { .f1 = g0 }; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}}
+}
+
+void testAssignment(void) {
+ ug0 = ug1; // expected-error {{cannot assign to a variable of type 'U0' since it is a union that is non-trivial to copy}}
+ sg0 = sg1; // expected-error {{cannot assign to a variable of type 'S0' since it contains a union that is non-trivial to copy}}
+}
+
+U0 ug2 = (U0){ .f1 = 0 }; // expected-error {{cannot copy-initialize an object of type 'U0' since it is a union that is non-trivial to copy}}
+S0 sg3 = (S0){ .f0 = {0}, .f1 = 0 }; // expected-error {{cannot copy-initialize an object of type 'S0' since it contains a union that is non-trivial to copy}}
+S0 *sg4 = &(S0){ .f1 = 0 }; // expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}}
+
+void testCompoundLiteral(void) {
+ const U0 *t0 = &(U0){ .f0 = g0 }; // expected-error {{cannot construct an automatic compound literal of type 'U0' since it is a union that is non-trivial to destruct}}
+ const U0 *t1 = &(U0){ .f1 = g0 }; // expected-error {{cannot construct an automatic compound literal of type 'U0' since it is a union that is non-trivial to destruct}}
+ const S0 *t2 = &(S0){ .f0 = ug0 }; // expected-error {{cannot construct an automatic compound literal of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot copy-initialize an object of type 'U0' since it is a union that is non-trivial to copy}}
+ const S0 *t3 = &(S0){ .f1 = g0 }; // expected-error {{cannot construct an automatic compound literal of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}}
+}
+
+typedef void (^BlockTy)(void);
+void escapingFunc(BlockTy);
+void noescapingFunc(__attribute__((noescape)) BlockTy);
+
+void testBlockCapture(void) {
+ U0 t0; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}}
+ S0 t1; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'S0' since it contains a union that is non-trivial to default-initialize}}
+ __block U0 t2; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}}
+ __block S0 t3; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'S0' since it contains a union that is non-trivial to default-initialize}}
+
+ escapingFunc(^{ g0 = t0.f0; }); // expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to copy}}
+ escapingFunc(^{ g0 = t1.f0.f0; }); // expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to copy}}
+ escapingFunc(^{ g0 = t2.f0; }); // expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to copy}}
+ escapingFunc(^{ g0 = t3.f0.f0; }); // expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to copy}}
+ noescapingFunc(^{ g0 = t0.f0; }); // expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to copy}}
+ noescapingFunc(^{ g0 = t1.f0.f0; }); // expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to copy}}
+ noescapingFunc(^{ g0 = t2.f0; });
+ noescapingFunc(^{ g0 = t3.f0.f0; });
+}
+
+void testVolatileLValueToRValue(volatile U0 *a) {
+ (void)*a; // expected-error {{cannot use volatile type 'volatile U0' where it causes an lvalue-to-rvalue conversion since it is a union that is non-trivial to destruct}} // expected-error {{cannot use volatile type 'volatile U0' where it causes an lvalue-to-rvalue conversion since it is a union that is non-trivial to copy}}
+}
From 087b044c4915717a51f8c0adb18eca5ae7a4f994 Mon Sep 17 00:00:00 2001
From: Nathan Ridge
Date: Sat, 13 Jul 2019 03:24:48 +0000
Subject: [PATCH 023/451] [clangd] Implement typeHierarchy/resolve for subtypes
Summary:
This allows the client to resolve subtypes one level at a time.
For supertypes, this is not necessary, because we eagerly compute
supertypes and return all levels.
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64308
llvm-svn: 365986
---
clang-tools-extra/clangd/ClangdLSPServer.cpp | 8 +++
clang-tools-extra/clangd/ClangdLSPServer.h | 2 +
clang-tools-extra/clangd/ClangdServer.cpp | 7 +++
clang-tools-extra/clangd/ClangdServer.h | 5 ++
clang-tools-extra/clangd/Protocol.cpp | 17 +++--
clang-tools-extra/clangd/Protocol.h | 23 +++++--
clang-tools-extra/clangd/XRefs.cpp | 25 +++++++-
clang-tools-extra/clangd/XRefs.h | 4 ++
.../clangd/test/type-hierarchy.test | 63 ++++++++++++++++++-
.../clangd/unittests/TypeHierarchyTests.cpp | 46 +++++++++++++-
10 files changed, 187 insertions(+), 13 deletions(-)
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 2b25058c9672c..5f8b307f721a6 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -926,6 +926,13 @@ void ClangdLSPServer::onTypeHierarchy(
Params.resolve, Params.direction, std::move(Reply));
}
+void ClangdLSPServer::onResolveTypeHierarchy(
+ const ResolveTypeHierarchyItemParams &Params,
+ Callback> Reply) {
+ Server->resolveTypeHierarchy(Params.item, Params.resolve, Params.direction,
+ std::move(Reply));
+}
+
void ClangdLSPServer::applyConfiguration(
const ConfigurationSettings &Settings) {
// Per-file update to the compilation database.
@@ -1021,6 +1028,7 @@ ClangdLSPServer::ClangdLSPServer(
MsgHandler->bind("workspace/didChangeConfiguration", &ClangdLSPServer::onChangeConfiguration);
MsgHandler->bind("textDocument/symbolInfo", &ClangdLSPServer::onSymbolInfo);
MsgHandler->bind("textDocument/typeHierarchy", &ClangdLSPServer::onTypeHierarchy);
+ MsgHandler->bind("typeHierarchy/resolve", &ClangdLSPServer::onResolveTypeHierarchy);
// clang-format on
}
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h
index 43e05b3dc8e55..1c37750a18526 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.h
+++ b/clang-tools-extra/clangd/ClangdLSPServer.h
@@ -100,6 +100,8 @@ class ClangdLSPServer : private DiagnosticsConsumer {
Callback>);
void onTypeHierarchy(const TypeHierarchyParams &,
Callback>);
+ void onResolveTypeHierarchy(const ResolveTypeHierarchyItemParams &,
+ Callback>);
void onChangeConfiguration(const DidChangeConfigurationParams &);
void onSymbolInfo(const TextDocumentPositionParams &,
Callback>);
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index 451dac6f0df4b..10949ef001c02 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -528,6 +528,13 @@ void ClangdServer::typeHierarchy(PathRef File, Position Pos, int Resolve,
WorkScheduler.runWithAST("Type Hierarchy", File, Bind(Action, std::move(CB)));
}
+void ClangdServer::resolveTypeHierarchy(
+ TypeHierarchyItem Item, int Resolve, TypeHierarchyDirection Direction,
+ Callback> CB) {
+ clangd::resolveTypeHierarchy(Item, Resolve, Direction, Index);
+ CB(Item);
+}
+
void ClangdServer::onFileEvent(const DidChangeWatchedFilesParams &Params) {
// FIXME: Do nothing for now. This will be used for indexing and potentially
// invalidating other caches.
diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
index ba39806eb72c4..fa6783b1f1c13 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -210,6 +210,11 @@ class ClangdServer {
TypeHierarchyDirection Direction,
Callback> CB);
+ /// Resolve type hierarchy item in the given direction.
+ void resolveTypeHierarchy(TypeHierarchyItem Item, int Resolve,
+ TypeHierarchyDirection Direction,
+ Callback> CB);
+
/// Retrieve the top symbols from the workspace matching a query.
void workspaceSymbols(StringRef Query, int Limit,
Callback> CB);
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index 7c70afb567df9..600896b1eeee6 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -422,8 +422,7 @@ bool fromJSON(const llvm::json::Value &Params,
bool fromJSON(const llvm::json::Value &Params,
DocumentRangeFormattingParams &R) {
llvm::json::ObjectMapper O(Params);
- return O && O.map("textDocument", R.textDocument) &&
- O.map("range", R.range);
+ return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
}
bool fromJSON(const llvm::json::Value &Params,
@@ -445,8 +444,8 @@ bool fromJSON(const llvm::json::Value &Params, DocumentSymbolParams &R) {
llvm::json::Value toJSON(const DiagnosticRelatedInformation &DRI) {
return llvm::json::Object{
- {"location", DRI.location},
- {"message", DRI.message},
+ {"location", DRI.location},
+ {"message", DRI.message},
};
}
@@ -978,6 +977,8 @@ llvm::json::Value toJSON(const TypeHierarchyItem &I) {
Result["parents"] = I.parents;
if (I.children)
Result["children"] = I.children;
+ if (I.data)
+ Result["data"] = I.data;
return std::move(Result);
}
@@ -996,10 +997,18 @@ bool fromJSON(const llvm::json::Value &Params, TypeHierarchyItem &I) {
O.map("deprecated", I.deprecated);
O.map("parents", I.parents);
O.map("children", I.children);
+ O.map("data", I.data);
return true;
}
+bool fromJSON(const llvm::json::Value &Params,
+ ResolveTypeHierarchyItemParams &P) {
+ llvm::json::ObjectMapper O(Params);
+ return O && O.map("item", P.item) && O.map("resolve", P.resolve) &&
+ O.map("direction", P.direction);
+}
+
bool fromJSON(const llvm::json::Value &Params, ReferenceParams &R) {
TextDocumentPositionParams &Base = R;
return fromJSON(Params, Base);
diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h
index 7a1a8c77d2591..a2c9438ea9d5d 100644
--- a/clang-tools-extra/clangd/Protocol.h
+++ b/clang-tools-extra/clangd/Protocol.h
@@ -1127,7 +1127,7 @@ struct TypeHierarchyItem {
SymbolKind kind;
/// `true` if the hierarchy item is deprecated. Otherwise, `false`.
- bool deprecated;
+ bool deprecated = false;
/// The URI of the text document where this type hierarchy item belongs to.
URIForFile uri;
@@ -1153,13 +1153,26 @@ struct TypeHierarchyItem {
/// descendants. If not defined, the children have not been resolved.
llvm::Optional> children;
- /// The protocol has a slot here for an optional 'data' filed, which can
- /// be used to identify a type hierarchy item in a resolve request. We don't
- /// need this (the item itself is sufficient to identify what to resolve)
- /// so don't declare it.
+ /// An optional 'data' filed, which can be used to identify a type hierarchy
+ /// item in a resolve request.
+ llvm::Optional data;
};
llvm::json::Value toJSON(const TypeHierarchyItem &);
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const TypeHierarchyItem &);
+bool fromJSON(const llvm::json::Value &, TypeHierarchyItem &);
+
+/// Parameters for the `typeHierarchy/resolve` request.
+struct ResolveTypeHierarchyItemParams {
+ /// The item to resolve.
+ TypeHierarchyItem item;
+
+ /// The hierarchy levels to resolve. `0` indicates no level.
+ int resolve;
+
+ /// The direction of the hierarchy levels to resolve.
+ TypeHierarchyDirection direction;
+};
+bool fromJSON(const llvm::json::Value &, ResolveTypeHierarchyItemParams &);
struct ReferenceParams : public TextDocumentPositionParams {
// For now, no options like context.includeDeclaration are supported.
diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index 1d34499b36edf..59f07ee405eed 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -893,7 +893,7 @@ llvm::Optional getDeducedType(ParsedAST &AST,
/// Retrieves the deduced type at a given location (auto, decltype).
bool hasDeducedType(ParsedAST &AST, SourceLocation SourceLocationBeg) {
- return (bool) getDeducedType(AST, SourceLocationBeg);
+ return (bool)getDeducedType(AST, SourceLocationBeg);
}
llvm::Optional getHover(ParsedAST &AST, Position Pos,
@@ -1104,6 +1104,10 @@ symbolToTypeHierarchyItem(const Symbol &S, const SymbolIndex *Index,
// (https://github.com/clangd/clangd/issues/59).
THI.range = THI.selectionRange;
THI.uri = Loc->uri;
+ // Store the SymbolID in the 'data' field. The client will
+ // send this back in typeHierarchy/resolve, allowing us to
+ // continue resolving additional levels of the type hierarchy.
+ THI.data = S.ID.str();
return std::move(THI);
}
@@ -1247,6 +1251,25 @@ getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels,
return Result;
}
+void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,
+ TypeHierarchyDirection Direction,
+ const SymbolIndex *Index) {
+ // We only support typeHierarchy/resolve for children, because for parents
+ // we ignore ResolveLevels and return all levels of parents eagerly.
+ if (Direction == TypeHierarchyDirection::Parents || ResolveLevels == 0)
+ return;
+
+ Item.children.emplace();
+
+ if (Index && Item.data) {
+ // We store the item's SymbolID in the 'data' field, and the client
+ // passes it back to us in typeHierarchy/resolve.
+ if (Expected ID = SymbolID::fromStr(*Item.data)) {
+ fillSubTypes(*ID, *Item.children, Index, ResolveLevels, Item.uri.file());
+ }
+ }
+}
+
FormattedString HoverInfo::present() const {
FormattedString Output;
if (NamespaceScope) {
diff --git a/clang-tools-extra/clangd/XRefs.h b/clang-tools-extra/clangd/XRefs.h
index 318133a572a28..3044036c17f15 100644
--- a/clang-tools-extra/clangd/XRefs.h
+++ b/clang-tools-extra/clangd/XRefs.h
@@ -141,6 +141,10 @@ llvm::Optional getTypeHierarchy(
ParsedAST &AST, Position Pos, int Resolve, TypeHierarchyDirection Direction,
const SymbolIndex *Index = nullptr, PathRef TUPath = PathRef{});
+void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,
+ TypeHierarchyDirection Direction,
+ const SymbolIndex *Index);
+
/// Retrieves the deduced type at a given location (auto, decltype).
/// Retuns None unless SourceLocationBeg starts an auto/decltype token.
/// It will return the underlying type.
diff --git a/clang-tools-extra/clangd/test/type-hierarchy.test b/clang-tools-extra/clangd/test/type-hierarchy.test
index 7161bd143bff3..b2e78ae249dcc 100644
--- a/clang-tools-extra/clangd/test/type-hierarchy.test
+++ b/clang-tools-extra/clangd/test/type-hierarchy.test
@@ -1,7 +1,7 @@
# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
---
-{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"struct Parent {};\nstruct Child1 : Parent {};\nstruct Child2 : Child1 {};\nstruct Child3 : Child2 {};"}}}
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"struct Parent {};\nstruct Child1 : Parent {};\nstruct Child2 : Child1 {};\nstruct Child3 : Child2 {};\nstruct Child4 : Child3 {};"}}}
---
{"jsonrpc":"2.0","id":1,"method":"textDocument/typeHierarchy","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":11},"direction":2,"resolve":1}}
# CHECK: "id": 1
@@ -9,6 +9,7 @@
# CHECK-NEXT: "result": {
# CHECK-NEXT: "children": [
# CHECK-NEXT: {
+# CHECK-NEXT: "data": "A6576FE083F2949A",
# CHECK-NEXT: "kind": 23,
# CHECK-NEXT: "name": "Child3",
# CHECK-NEXT: "range": {
@@ -114,6 +115,64 @@
# CHECK-NEXT: "uri": "file:///clangd-test/main.cpp"
# CHECK-NEXT: }
---
-{"jsonrpc":"2.0","id":2,"method":"shutdown"}
+{"jsonrpc":"2.0","id":2,"method":"typeHierarchy/resolve","params":{"item":{"uri":"test:///main.cpp","data":"A6576FE083F2949A","name":"Child3","kind":23,"range":{"end":{"character":13,"line":3},"start":{"character":7,"line":3}},"selectionRange":{"end":{"character":13,"line":3},"start":{"character":7,"line":3}}},"direction":0,"resolve":1}}
+# CHECK: "id": 2
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "children": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "data": "5705B382DFC77CBC",
+# CHECK-NEXT: "kind": 23,
+# CHECK-NEXT: "name": "Child4",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 13,
+# CHECK-NEXT: "line": 4
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 7,
+# CHECK-NEXT: "line": 4
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "selectionRange": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 13,
+# CHECK-NEXT: "line": 4
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 7,
+# CHECK-NEXT: "line": 4
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "uri": "file:///clangd-test/main.cpp"
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "data": "A6576FE083F2949A",
+# CHECK-NEXT: "kind": 23,
+# CHECK-NEXT: "name": "Child3",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 13,
+# CHECK-NEXT: "line": 3
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 7,
+# CHECK-NEXT: "line": 3
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "selectionRange": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 13,
+# CHECK-NEXT: "line": 3
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 7,
+# CHECK-NEXT: "line": 3
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "uri": "file:///clangd-test/main.cpp"
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
---
{"jsonrpc":"2.0","method":"exit"}
diff --git a/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp b/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp
index be16646a72036..633a25fe3b442 100644
--- a/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp
+++ b/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp
@@ -42,8 +42,17 @@ MATCHER_P(WithKind, Kind, "") { return arg.kind == Kind; }
MATCHER_P(SelectionRangeIs, R, "") { return arg.selectionRange == R; }
template
::testing::Matcher Parents(ParentMatchers... ParentsM) {
- return Field(&TypeHierarchyItem::parents, HasValue(ElementsAre(ParentsM...)));
+ return Field(&TypeHierarchyItem::parents,
+ HasValue(UnorderedElementsAre(ParentsM...)));
}
+template
+::testing::Matcher Children(ChildMatchers... ChildrenM) {
+ return Field(&TypeHierarchyItem::children,
+ HasValue(UnorderedElementsAre(ChildrenM...)));
+}
+// Note: "not resolved" is differnt from "resolved but empty"!
+MATCHER(ParentsNotResolved, "") { return !arg.parents; }
+MATCHER(ChildrenNotResolved, "") { return !arg.children; }
TEST(FindRecordTypeAt, TypeOrVariable) {
Annotations Source(R"cpp(
@@ -603,6 +612,41 @@ struct Child : Parent {};
EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
}
+TEST(Subtypes, LazyResolution) {
+ Annotations Source(R"cpp(
+struct P^arent {};
+struct Child1 : Parent {};
+struct Child2a : Child1 {};
+struct Child2b : Child1 {};
+)cpp");
+
+ TestTU TU = TestTU::withCode(Source.code());
+ auto AST = TU.build();
+ auto Index = TU.index();
+
+ llvm::Optional Result = getTypeHierarchy(
+ AST, Source.point(), /*ResolveLevels=*/1,
+ TypeHierarchyDirection::Children, Index.get(), testPath(TU.Filename));
+ ASSERT_TRUE(bool(Result));
+ EXPECT_THAT(
+ *Result,
+ AllOf(WithName("Parent"), WithKind(SymbolKind::Struct), Parents(),
+ Children(AllOf(WithName("Child1"), WithKind(SymbolKind::Struct),
+ ParentsNotResolved(), ChildrenNotResolved()))));
+
+ resolveTypeHierarchy((*Result->children)[0], /*ResolveLevels=*/1,
+ TypeHierarchyDirection::Children, Index.get());
+
+ EXPECT_THAT(
+ (*Result->children)[0],
+ AllOf(WithName("Child1"), WithKind(SymbolKind::Struct),
+ ParentsNotResolved(),
+ Children(AllOf(WithName("Child2a"), WithKind(SymbolKind::Struct),
+ ParentsNotResolved(), ChildrenNotResolved()),
+ AllOf(WithName("Child2b"), WithKind(SymbolKind::Struct),
+ ParentsNotResolved(), ChildrenNotResolved()))));
+}
+
} // namespace
} // namespace clangd
} // namespace clang
From d1fdadb22685b88d885833f4a21cca5df45fa303 Mon Sep 17 00:00:00 2001
From: Nathan Ridge
Date: Sat, 13 Jul 2019 03:24:54 +0000
Subject: [PATCH 024/451] [clangd] Mark type hierarchy as a supported feature
in the docs
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64614
llvm-svn: 365987
---
clang-tools-extra/docs/clangd/Features.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/clangd/Features.rst b/clang-tools-extra/docs/clangd/Features.rst
index 3e6e745a691c8..87b6713c44ace 100644
--- a/clang-tools-extra/docs/clangd/Features.rst
+++ b/clang-tools-extra/docs/clangd/Features.rst
@@ -261,7 +261,7 @@ developed outside clangd or become clangd extensions to LSP.
+-------------------------------------+------------+----------+
| Call hierarchy | No | No |
+-------------------------------------+------------+----------+
-| Type hierarchy | No | No |
+| Type hierarchy | No | Yes |
+-------------------------------------+------------+----------+
| Organize Includes | No | No |
+-------------------------------------+------------+----------+
From 497bb44fc41f2e9c4d3c5ed8f525da01fa476979 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere
Date: Sat, 13 Jul 2019 03:30:55 +0000
Subject: [PATCH 025/451] Make Python version setting actually effective
This needs to be outside the if to actually work. Also, this adjusts the
list of versions to match LLVM.
Patch by: Christian Biesinger
Differential revision: https://reviews.llvm.org/D64578
llvm-svn: 365988
---
lldb/cmake/modules/LLDBStandalone.cmake | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/cmake/modules/LLDBStandalone.cmake b/lldb/cmake/modules/LLDBStandalone.cmake
index 80075b91b6e40..803f6bda968b2 100644
--- a/lldb/cmake/modules/LLDBStandalone.cmake
+++ b/lldb/cmake/modules/LLDBStandalone.cmake
@@ -87,8 +87,8 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
include(CheckAtomic)
include(LLVMDistributionSupport)
+ set(Python_ADDITIONAL_VERSIONS 3.7 3.6 3.5 2.7)
if (PYTHON_EXECUTABLE STREQUAL "")
- set(Python_ADDITIONAL_VERSIONS 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0 2.7 2.6 2.5)
include(FindPythonInterp)
if( NOT PYTHONINTERP_FOUND )
message(FATAL_ERROR
From 118ee5f2e06a9972bd9fd171444cc080c03b0b99 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka
Date: Sat, 13 Jul 2019 03:59:55 +0000
Subject: [PATCH 026/451] Initialize the non-trivial C union bits I added to
RecordDeclBitfields in r365985
These bits weren't being initialized in the RecordDecl's constructor,
which probably caused test/Modules/stress1.cpp to fail on a couple of
bots.
llvm-svn: 365989
---
clang/lib/AST/Decl.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 21dd5425834a9..21cf9da18a8b2 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -4252,6 +4252,9 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C,
setNonTrivialToPrimitiveDefaultInitialize(false);
setNonTrivialToPrimitiveCopy(false);
setNonTrivialToPrimitiveDestroy(false);
+ setHasNonTrivialToPrimitiveDefaultInitializeCUnion(false);
+ setHasNonTrivialToPrimitiveDestructCUnion(false);
+ setHasNonTrivialToPrimitiveCopyCUnion(false);
setParamDestroyedInCallee(false);
setArgPassingRestrictions(APK_CanPassInRegs);
}
From 1a6053ebc61cb0b8146f5ca27b74859a9a91e0a3 Mon Sep 17 00:00:00 2001
From: Petr Hosek
Date: Sat, 13 Jul 2019 05:31:48 +0000
Subject: [PATCH 027/451] Revert "[COFF] Add null check in case of symbols
defined in LTO blobs"
This reverts commit r365979: COFF/undefined-symbol-lto.test is failing.
llvm-svn: 365990
---
lld/COFF/SymbolTable.cpp | 2 +-
.../COFF/Inputs/undefined-symbol-lto-a.ll | 82 -------------------
.../COFF/Inputs/undefined-symbol-lto-b.ll | 29 -------
lld/test/COFF/undefined-symbol-lto.test | 30 -------
4 files changed, 1 insertion(+), 142 deletions(-)
delete mode 100644 lld/test/COFF/Inputs/undefined-symbol-lto-a.ll
delete mode 100644 lld/test/COFF/Inputs/undefined-symbol-lto-b.ll
delete mode 100644 lld/test/COFF/undefined-symbol-lto.test
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 2173c10c1ca56..280a9c28892c8 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -69,7 +69,7 @@ static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {
for (Symbol *s : sc->file->getSymbols()) {
auto *d = dyn_cast_or_null(s);
- if (!d || !d->data || d->getChunk() != sc || d->getValue() > addr ||
+ if (!d || d->getChunk() != sc || d->getValue() > addr ||
(candidate && d->getValue() < candidate->getValue()))
continue;
diff --git a/lld/test/COFF/Inputs/undefined-symbol-lto-a.ll b/lld/test/COFF/Inputs/undefined-symbol-lto-a.ll
deleted file mode 100644
index 6793ec718e806..0000000000000
--- a/lld/test/COFF/Inputs/undefined-symbol-lto-a.ll
+++ /dev/null
@@ -1,82 +0,0 @@
-; ModuleID = 't.obj'
-source_filename = "t.cpp"
-target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-pc-windows-msvc19.21.27702"
-
-%struct.Init = type { %struct.S }
-%struct.S = type { i32 (...)** }
-%rtti.CompleteObjectLocator = type { i32, i32, i32, i32, i32, i32 }
-%rtti.TypeDescriptor7 = type { i8**, i8*, [8 x i8] }
-%rtti.ClassHierarchyDescriptor = type { i32, i32, i32, i32 }
-%rtti.BaseClassDescriptor = type { i32, i32, i32, i32, i32, i32, i32 }
-
-$"??_SS@@6B@" = comdat largest
-
-$"??_R4S@@6B@" = comdat any
-
-$"??_R0?AUS@@@8" = comdat any
-
-$"??_R3S@@8" = comdat any
-
-$"??_R2S@@8" = comdat any
-
-$"??_R1A@?0A@EA@S@@8" = comdat any
-
-@"?d@@3UInit@@A" = dso_local local_unnamed_addr global %struct.Init zeroinitializer, align 8
-@anon.bcb2691509de99310dddb690fcdb4cdc.0 = private unnamed_addr constant { [2 x i8*] } { [2 x i8*] [i8* bitcast (%rtti.CompleteObjectLocator* @"??_R4S@@6B@" to i8*), i8* bitcast (void (%struct.S*)* @"?foo@S@@UEAAXXZ" to i8*)] }, comdat($"??_SS@@6B@"), !type !0
-@"??_R4S@@6B@" = linkonce_odr constant %rtti.CompleteObjectLocator { i32 1, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"??_R0?AUS@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"??_R3S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.CompleteObjectLocator* @"??_R4S@@6B@" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat
-@"??_7type_info@@6B@" = external constant i8*
-@"??_R0?AUS@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"??_7type_info@@6B@", i8* null, [8 x i8] c".?AUS@@\00" }, comdat
-@__ImageBase = external dso_local constant i8
-@"??_R3S@@8" = linkonce_odr constant %rtti.ClassHierarchyDescriptor { i32 0, i32 0, i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint ([2 x i32]* @"??_R2S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat
-@"??_R2S@@8" = linkonce_odr constant [2 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.BaseClassDescriptor* @"??_R1A@?0A@EA@S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0], comdat
-@"??_R1A@?0A@EA@S@@8" = linkonce_odr constant %rtti.BaseClassDescriptor { i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"??_R0?AUS@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 0, i32 -1, i32 0, i32 64, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"??_R3S@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat
-@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_t.cpp, i8* null }]
-
-@"??_SS@@6B@" = unnamed_addr alias i8*, getelementptr inbounds ({ [2 x i8*] }, { [2 x i8*] }* @anon.bcb2691509de99310dddb690fcdb4cdc.0, i32 0, i32 0, i32 1)
-
-declare dso_local void @"?undefined_ref@@YAXXZ"() local_unnamed_addr #0
-
-declare dllimport void @"?foo@S@@UEAAXXZ"(%struct.S*) unnamed_addr #0
-
-; Function Attrs: nounwind sspstrong uwtable
-define internal void @_GLOBAL__sub_I_t.cpp() #1 {
-entry:
- store i32 (...)** bitcast (i8** @"??_SS@@6B@" to i32 (...)**), i32 (...)*** getelementptr inbounds (%struct.Init, %struct.Init* @"?d@@3UInit@@A", i64 0, i32 0, i32 0), align 8
- tail call void @"?undefined_ref@@YAXXZ"() #2
- ret void
-}
-
-attributes #0 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #1 = { nounwind sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #2 = { nounwind }
-
-!llvm.linker.options = !{!1, !2}
-!llvm.module.flags = !{!3, !4, !5, !6}
-!llvm.ident = !{!7}
-
-!0 = !{i64 8, !"?AUS@@"}
-!1 = !{!"/DEFAULTLIB:libcmt.lib"}
-!2 = !{!"/DEFAULTLIB:oldnames.lib"}
-!3 = !{i32 1, !"wchar_size", i32 2}
-!4 = !{i32 7, !"PIC Level", i32 2}
-!5 = !{i32 1, !"ThinLTO", i32 0}
-!6 = !{i32 1, !"EnableSplitLTOUnit", i32 0}
-!7 = !{!"clang version 9.0.0 (git@github.com:llvm/llvm-project.git 1a285c27fdf6407ceed3398e015d00559f5f533d)"}
-
-^0 = module: (path: "t.obj", hash: (0, 0, 0, 0, 0))
-^1 = gv: (name: "__ImageBase") ; guid = 434928772013489304
-^2 = gv: (name: "??_R2S@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^1, ^6)))) ; guid = 2160898732728284029
-^3 = gv: (name: "llvm.global_ctors", summaries: (variable: (module: ^0, flags: (linkage: appending, notEligibleToImport: 1, live: 1, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^14)))) ; guid = 2412314959268824392
-^4 = gv: (name: "?foo@S@@UEAAXXZ") ; guid = 6578172636330484861
-^5 = gv: (name: "??_SS@@6B@", summaries: (alias: (module: ^0, flags: (linkage: external, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), aliasee: ^10))) ; guid = 8774897714842691026
-^6 = gv: (name: "??_R1A@?0A@EA@S@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^11, ^1, ^8)))) ; guid = 9397802696236423453
-^7 = gv: (name: "?undefined_ref@@YAXXZ") ; guid = 9774674600202276560
-^8 = gv: (name: "??_R3S@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^1, ^2)))) ; guid = 10685958509605791599
-^9 = gv: (name: "??_7type_info@@6B@") ; guid = 10826752452437539368
-^10 = gv: (name: "anon.bcb2691509de99310dddb690fcdb4cdc.0", summaries: (variable: (module: ^0, flags: (linkage: private, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), vTableFuncs: ((virtFunc: ^4, offset: 8)), refs: (^13, ^4)))) ; guid = 11510395461204283992
-^11 = gv: (name: "??_R0?AUS@@@8", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^9)))) ; guid = 12346607659584231960
-^12 = gv: (name: "?d@@3UInit@@A", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), varFlags: (readonly: 1, writeonly: 1)))) ; guid = 14563354643524156382
-^13 = gv: (name: "??_R4S@@6B@", summaries: (variable: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 1, live: 0, dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0, writeonly: 0), refs: (^13, ^11, ^1, ^8)))) ; guid = 14703528065171087394
-^14 = gv: (name: "_GLOBAL__sub_I_t.cpp", summaries: (function: (module: ^0, flags: (linkage: internal, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 3, calls: ((callee: ^7)), refs: (^12, ^5)))) ; guid = 15085897428757412588
-^15 = typeidCompatibleVTable: (name: "?AUS@@", summary: ((offset: 8, ^10))) ; guid = 13986515119763165370
diff --git a/lld/test/COFF/Inputs/undefined-symbol-lto-b.ll b/lld/test/COFF/Inputs/undefined-symbol-lto-b.ll
deleted file mode 100644
index ff73e7c6ba680..0000000000000
--- a/lld/test/COFF/Inputs/undefined-symbol-lto-b.ll
+++ /dev/null
@@ -1,29 +0,0 @@
-; ModuleID = 'b.obj'
-source_filename = "b.cpp"
-target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-pc-windows-msvc19.21.27702"
-
-%struct.S = type { i32 (...)** }
-
-; Function Attrs: norecurse nounwind readnone sspstrong uwtable
-define dso_local void @"?foo@S@@UEAAXXZ"(%struct.S* nocapture %this) unnamed_addr #0 align 2 {
-entry:
- ret void
-}
-
-attributes #0 = { norecurse nounwind readnone sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
-
-!llvm.linker.options = !{!0, !1}
-!llvm.module.flags = !{!2, !3, !4, !5}
-!llvm.ident = !{!6}
-
-!0 = !{!"/DEFAULTLIB:libcmt.lib"}
-!1 = !{!"/DEFAULTLIB:oldnames.lib"}
-!2 = !{i32 1, !"wchar_size", i32 2}
-!3 = !{i32 7, !"PIC Level", i32 2}
-!4 = !{i32 1, !"ThinLTO", i32 0}
-!5 = !{i32 1, !"EnableSplitLTOUnit", i32 0}
-!6 = !{!"clang version 9.0.0 (git@github.com:llvm/llvm-project.git 1a285c27fdf6407ceed3398e015d00559f5f533d)"}
-
-^0 = module: (path: "b.obj", hash: (0, 0, 0, 0, 0))
-^1 = gv: (name: "?foo@S@@UEAAXXZ", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0), insts: 1, funcFlags: (readNone: 1, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0, noInline: 0)))) ; guid = 6578172636330484861
diff --git a/lld/test/COFF/undefined-symbol-lto.test b/lld/test/COFF/undefined-symbol-lto.test
deleted file mode 100644
index 6911b121122a4..0000000000000
--- a/lld/test/COFF/undefined-symbol-lto.test
+++ /dev/null
@@ -1,30 +0,0 @@
-RUN: rm -rf %t && mkdir -p %t && cd %t
-RUN: llvm-as %S/Inputs/undefined-symbol-lto-a.ll -o t.obj
-RUN: llvm-as %S/Inputs/undefined-symbol-lto-b.ll -o b.obj
-RUN: llvm-lib b.obj -out:b.lib
-RUN: not lld-link t.obj b.lib -subsystem:console 2>&1 | FileCheck %s
-
-CHECK: undefined symbol: main
-CHECK: referenced by
-CHECK: undefined symbol: void __cdecl undefined_ref(void)
-CHECK: referenced by
-
-Originally reported as PR42536.
-
-a.ll corresponds to this C++:
-
-struct __declspec(dllimport) S {
- virtual void foo();
-};
-void undefined_ref();
-struct Init {
- Init() { undefined_ref(); }
- S c;
-} d;
-
-b.ll is from this C++:
-
-struct S {
- virtual void foo();
-};
-void S::foo() {}
From 1447b60eeb2b3026a0c96bef052843a71002d617 Mon Sep 17 00:00:00 2001
From: Michal Gorny
Date: Sat, 13 Jul 2019 06:24:14 +0000
Subject: [PATCH 028/451] [lldb] [test] Un-XFAIL TestFormattersSBAPI on NetBSD
llvm-svn: 365991
---
.../lldbsuite/test/python_api/formatters/TestFormattersSBAPI.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/lldb/packages/Python/lldbsuite/test/python_api/formatters/TestFormattersSBAPI.py b/lldb/packages/Python/lldbsuite/test/python_api/formatters/TestFormattersSBAPI.py
index dd12ac198cd35..8548506fdc463 100644
--- a/lldb/packages/Python/lldbsuite/test/python_api/formatters/TestFormattersSBAPI.py
+++ b/lldb/packages/Python/lldbsuite/test/python_api/formatters/TestFormattersSBAPI.py
@@ -22,7 +22,6 @@ def setUp(self):
self.line = line_number('main.cpp', '// Set break point at this line.')
@add_test_categories(['pyapi'])
- @expectedFailureNetBSD
def test_formatters_api(self):
"""Test Python APIs for working with formatters"""
self.build()
From 21a92a8a559ba27907290bafd181e490101a4fcb Mon Sep 17 00:00:00 2001
From: Sylvestre Ledru
Date: Sat, 13 Jul 2019 06:27:35 +0000
Subject: [PATCH 029/451] This reverts commit
632a36bfcfc8273c1861f04ff6758d863c47c784.
Some targets such as Python 2.7.16 still use VERSION in
their builds. Without VERSION defined, the source code
has syntax errors.
Reverting as it will probably break many other things.
Noticed by Sterling Augustine
llvm-svn: 365992
---
clang/docs/LanguageExtensions.rst | 2 --
clang/docs/ReleaseNotes.rst | 10 ----------
clang/lib/Basic/Version.cpp | 2 ++
clang/lib/Frontend/InitPreprocessor.cpp | 6 ++++++
clang/test/Index/complete-exprs.c | 2 ++
clang/test/Preprocessor/init.c | 4 ++++
clang/utils/builtin-defines.c | 1 +
7 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 61152a251bdba..ecbf04c3c822a 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -324,8 +324,6 @@ option for a warning and returns true if that is a valid warning option.
...
#endif
-.. _languageextensions-builtin-macros:
-
Builtin Macros
==============
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7185030a92d7c..f0a35050dde08 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -56,11 +56,6 @@ Improvements to Clang's diagnostics
Non-comprehensive list of changes in this release
-------------------------------------------------
-- The ``__VERSION__`` macro has been removed.
- Previously this macro was set to a string aiming to achieve compatibility with
- GCC 4.2.1, but that should no longer be necessary. To get Clang's version,
- use the :ref:`clang namespaced version macros `.
-
- ...
@@ -84,11 +79,6 @@ Modified Compiler Flags
- ...
-Removed Compiler Options
-------------------------
-
-- ...
-
New Pragmas in Clang
--------------------
diff --git a/clang/lib/Basic/Version.cpp b/clang/lib/Basic/Version.cpp
index 5fd12762b6893..d6564582e7726 100644
--- a/clang/lib/Basic/Version.cpp
+++ b/clang/lib/Basic/Version.cpp
@@ -136,6 +136,8 @@ std::string getClangToolFullVersion(StringRef ToolName) {
}
std::string getClangFullCPPVersion() {
+ // The version string we report in __VERSION__ is just a compacted version of
+ // the one we report on the command line.
std::string buf;
llvm::raw_string_ostream OS(buf);
#ifdef CLANG_VENDOR
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index a02c266c094a8..1741ba5e5203e 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -604,6 +604,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Support for #pragma redefine_extname (Sun compatibility)
Builder.defineMacro("__PRAGMA_REDEFINE_EXTNAME", "1");
+ // As sad as it is, enough software depends on the __VERSION__ for version
+ // checks that it is necessary to report 4.2.1 (the base GCC version we claim
+ // compatibility with) first.
+ Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible " +
+ Twine(getClangFullCPPVersion()) + "\"");
+
// Initialize language-specific preprocessor defines.
// Standard conforming mode?
diff --git a/clang/test/Index/complete-exprs.c b/clang/test/Index/complete-exprs.c
index 50f5025f1512f..9beb16deef99b 100644
--- a/clang/test/Index/complete-exprs.c
+++ b/clang/test/Index/complete-exprs.c
@@ -27,6 +27,7 @@ void f5(float f) {
// RUN: c-index-test -code-completion-at=%s:7:10 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:10 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: NotImplemented:{TypedText __PRETTY_FUNCTION__} (65)
+// CHECK-CC1: macro definition:{TypedText __VERSION__} (70)
// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (12) (unavailable)
// CHECK-CC1-NOT: NotImplemented:{TypedText float} (65)
// CHECK-CC1: ParmDecl:{ResultType int}{TypedText j} (8)
@@ -38,6 +39,7 @@ void f5(float f) {
// RUN: c-index-test -code-completion-at=%s:7:18 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
// RUN: c-index-test -code-completion-at=%s:7:22 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s
// RUN: c-index-test -code-completion-at=%s:7:2 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: macro definition:{TypedText __VERSION__} (70)
// CHECK-CC2: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50)
// CHECK-CC2: NotImplemented:{TypedText float} (50)
// CHECK-CC2: ParmDecl:{ResultType int}{TypedText j} (34)
diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c
index 00a7c7b6bae95..8df3b4bd2ccf4 100644
--- a/clang/test/Preprocessor/init.c
+++ b/clang/test/Preprocessor/init.c
@@ -101,6 +101,7 @@
// COMMON:#define __ORDER_PDP_ENDIAN__ 3412
// COMMON:#define __STDC_HOSTED__ 1
// COMMON:#define __STDC__ 1
+// COMMON:#define __VERSION__ {{.*}}
// COMMON:#define __clang__ 1
// COMMON:#define __clang_major__ {{[0-9]+}}
// COMMON:#define __clang_minor__ {{[0-9]+}}
@@ -8168,6 +8169,7 @@
// SPARC:#define __UINT_LEAST8_MAX__ 255
// SPARC:#define __UINT_LEAST8_TYPE__ unsigned char
// SPARC:#define __USER_LABEL_PREFIX__
+// SPARC:#define __VERSION__ "4.2.1 Compatible{{.*}}
// SPARC:#define __WCHAR_MAX__ 2147483647
// SPARC:#define __WCHAR_TYPE__ int
// SPARC:#define __WCHAR_WIDTH__ 32
@@ -9039,6 +9041,7 @@
// X86_64-CLOUDABI:#define __UINT_LEAST8_MAX__ 255
// X86_64-CLOUDABI:#define __UINT_LEAST8_TYPE__ unsigned char
// X86_64-CLOUDABI:#define __USER_LABEL_PREFIX__
+// X86_64-CLOUDABI:#define __VERSION__ "4.2.1 Compatible{{.*}}
// X86_64-CLOUDABI:#define __WCHAR_MAX__ 2147483647
// X86_64-CLOUDABI:#define __WCHAR_TYPE__ int
// X86_64-CLOUDABI:#define __WCHAR_WIDTH__ 32
@@ -10040,6 +10043,7 @@
// WEBASSEMBLY-NEXT:#define __UINT_LEAST8_MAX__ 255
// WEBASSEMBLY-NEXT:#define __UINT_LEAST8_TYPE__ unsigned char
// WEBASSEMBLY-NEXT:#define __USER_LABEL_PREFIX__
+// WEBASSEMBLY-NEXT:#define __VERSION__ "{{.*}}"
// WEBASSEMBLY-NEXT:#define __WCHAR_MAX__ 2147483647
// WEBASSEMBLY-NEXT:#define __WCHAR_TYPE__ int
// WEBASSEMBLY-NOT:#define __WCHAR_UNSIGNED__
diff --git a/clang/utils/builtin-defines.c b/clang/utils/builtin-defines.c
index 2936d631e61a7..9bbe5be250269 100644
--- a/clang/utils/builtin-defines.c
+++ b/clang/utils/builtin-defines.c
@@ -49,6 +49,7 @@ RUN: done;
#undef __INT8_TYPE__
#undef __SSP__
#undef __APPLE_CC__
+#undef __VERSION__
#undef __clang__
#undef __llvm__
#undef __nocona
From 36fbd0da5fb7ac70146d2118165556d4af19fd8b Mon Sep 17 00:00:00 2001
From: Fangrui Song
Date: Sat, 13 Jul 2019 07:23:12 +0000
Subject: [PATCH 030/451] Simplify with llvm::is_contained. NFC
llvm-svn: 365993
---
.../clang-tidy/bugprone/AssertSideEffectCheck.cpp | 3 +--
.../bugprone/ForwardingReferenceOverloadCheck.cpp | 2 +-
clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp | 7 ++-----
clang-tools-extra/modularize/Modularize.cpp | 2 +-
4 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp
index a28ef1138e539..4e3f76544dc8b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp
@@ -108,8 +108,7 @@ void AssertSideEffectCheck::check(const MatchFinder::MatchResult &Result) {
StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LangOpts);
// Check if this macro is an assert.
- if (std::find(AssertMacros.begin(), AssertMacros.end(), MacroName) !=
- AssertMacros.end()) {
+ if (llvm::is_contained(AssertMacros, MacroName)) {
AssertMacroName = MacroName;
break;
}
diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp
index 57055ff2191e8..2773d38420be3 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp
@@ -105,7 +105,7 @@ void ForwardingReferenceOverloadCheck::check(
// template as the function parameter of that type. (This implies that type
// deduction will happen on the type.)
const TemplateParameterList *Params = FuncTemplate->getTemplateParameters();
- if (std::find(Params->begin(), Params->end(), TypeParmDecl) == Params->end())
+ if (!llvm::is_contained(*Params, TypeParmDecl))
return;
// Every parameter after the first must have a default value.
diff --git a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
index 45e59c3ec51ab..d0a95d95ec4b4 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -242,10 +242,8 @@ class CastSequenceVisitor : public RecursiveASTVisitor {
getOutermostMacroName(StartLoc, SM, Context.getLangOpts());
// Check to see if the user wants to replace the macro being expanded.
- if (std::find(NullMacros.begin(), NullMacros.end(), OutermostMacroName) ==
- NullMacros.end()) {
+ if (!llvm::is_contained(NullMacros, OutermostMacroName))
return skipSubTree();
- }
StartLoc = SM.getFileLoc(StartLoc);
EndLoc = SM.getFileLoc(EndLoc);
@@ -327,8 +325,7 @@ class CastSequenceVisitor : public RecursiveASTVisitor {
StringRef Name =
Lexer::getImmediateMacroName(OldArgLoc, SM, Context.getLangOpts());
- return std::find(NullMacros.begin(), NullMacros.end(), Name) !=
- NullMacros.end();
+ return llvm::is_contained(NullMacros, Name);
}
MacroLoc = SM.getExpansionRange(ArgLoc).getBegin();
diff --git a/clang-tools-extra/modularize/Modularize.cpp b/clang-tools-extra/modularize/Modularize.cpp
index 59fc5c351ff27..866356d055b62 100644
--- a/clang-tools-extra/modularize/Modularize.cpp
+++ b/clang-tools-extra/modularize/Modularize.cpp
@@ -369,7 +369,7 @@ getModularizeArgumentsAdjuster(DependencyMap &Dependencies) {
// Ignore warnings. (Insert after "clang_tool" at beginning.)
NewArgs.insert(NewArgs.begin() + 1, "-w");
// Since we are compiling .h files, assume C++ unless given a -x option.
- if (std::find(NewArgs.begin(), NewArgs.end(), "-x") == NewArgs.end()) {
+ if (!llvm::is_contained(NewArgs, "-x")) {
NewArgs.insert(NewArgs.begin() + 2, "-x");
NewArgs.insert(NewArgs.begin() + 3, "c++");
}
From 20d34eacf3f118d1e94165beaf3da24a5c1e8011 Mon Sep 17 00:00:00 2001
From: Petr Hosek
Date: Sat, 13 Jul 2019 08:07:10 +0000
Subject: [PATCH 031/451] [CMake][Fuchsia] Define asan+noexcept multilib
Using noexcept multilib with -fno-exceptions can lead to significant
space savings when statically linking libc++abi because we don't need
all the unwinding and demangling code.
When compiling with ASan, we already get a lot of overhead from the
instrumentation itself, when statically linking libc++abi, that overhead
is even larger.
Having the noexcept variant for ASan can help significantly, we've seen
more than 50% size reduction in our system image, which offsets the cost
of having to build another multilib.
Differential Revision: https://reviews.llvm.org/D64140
llvm-svn: 365994
---
clang/cmake/caches/Fuchsia-stage2.cmake | 10 +++++++++-
clang/lib/Driver/ToolChains/Fuchsia.cpp | 5 +++++
.../lib/aarch64-fuchsia/c++/asan+noexcept/libc++.so | 0
.../lib/x86_64-fuchsia/c++/asan+noexcept/libc++.so | 0
clang/test/Driver/fuchsia.cpp | 3 ++-
5 files changed, 16 insertions(+), 2 deletions(-)
create mode 100644 clang/test/Driver/Inputs/basic_fuchsia_tree/lib/aarch64-fuchsia/c++/asan+noexcept/libc++.so
create mode 100644 clang/test/Driver/Inputs/basic_fuchsia_tree/lib/x86_64-fuchsia/c++/asan+noexcept/libc++.so
diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake
index e93b6e4f07ad8..1f8a9e78763fa 100644
--- a/clang/cmake/caches/Fuchsia-stage2.cmake
+++ b/clang/cmake/caches/Fuchsia-stage2.cmake
@@ -153,13 +153,21 @@ if(FUCHSIA_SDK)
set(RUNTIMES_${target}-unknown-fuchsia+noexcept_LIBCXXABI_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
set(RUNTIMES_${target}-unknown-fuchsia+noexcept_LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
+ set(RUNTIMES_${target}-unknown-fuchsia+asan+noexcept_LLVM_BUILD_COMPILER_RT OFF CACHE BOOL "")
+ set(RUNTIMES_${target}-unknown-fuchsia+asan+noexcept_LLVM_USE_SANITIZER "Address" CACHE STRING "")
+ set(RUNTIMES_${target}-unknown-fuchsia+asan+noexcept_LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS OFF CACHE BOOL "")
+ set(RUNTIMES_${target}-unknown-fuchsia+asan+noexcept_LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS OFF CACHE BOOL "")
+ set(RUNTIMES_${target}-unknown-fuchsia+asan+noexcept_LIBCXXABI_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
+ set(RUNTIMES_${target}-unknown-fuchsia+asan+noexcept_LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
+
# Use .build-id link.
list(APPEND RUNTIME_BUILD_ID_LINK "${target}-unknown-fuchsia")
endforeach()
- set(LLVM_RUNTIME_MULTILIBS "asan;noexcept" CACHE STRING "")
+ set(LLVM_RUNTIME_MULTILIBS "asan;noexcept;asan+noexcept" CACHE STRING "")
set(LLVM_RUNTIME_MULTILIB_asan_TARGETS "x86_64-unknown-fuchsia;aarch64-unknown-fuchsia" CACHE STRING "")
set(LLVM_RUNTIME_MULTILIB_noexcept_TARGETS "x86_64-unknown-fuchsia;aarch64-unknown-fuchsia" CACHE STRING "")
+ set(LLVM_RUNTIME_MULTILIB_asan+noexcept_TARGETS "x86_64-unknown-fuchsia;aarch64-unknown-fuchsia" CACHE STRING "")
endif()
set(LLVM_BUILTIN_TARGETS "${BUILTIN_TARGETS}" CACHE STRING "")
diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp
index 2344a69adb962..1f5ec9ebb16d5 100644
--- a/clang/lib/Driver/ToolChains/Fuchsia.cpp
+++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp
@@ -192,6 +192,11 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
// ASan has higher priority because we always want the instrumentated version.
Multilibs.push_back(Multilib("asan", {}, {}, 2)
.flag("+fsanitize=address"));
+ // Use the asan+noexcept variant with ASan and -fno-exceptions.
+ Multilibs.push_back(Multilib("asan+noexcept", {}, {}, 3)
+ .flag("+fsanitize=address")
+ .flag("-fexceptions")
+ .flag("+fno-exceptions"));
Multilibs.FilterOut([&](const Multilib &M) {
std::vector RD = FilePaths(M);
return std::all_of(RD.begin(), RD.end(), [&](std::string P) {
diff --git a/clang/test/Driver/Inputs/basic_fuchsia_tree/lib/aarch64-fuchsia/c++/asan+noexcept/libc++.so b/clang/test/Driver/Inputs/basic_fuchsia_tree/lib/aarch64-fuchsia/c++/asan+noexcept/libc++.so
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/clang/test/Driver/Inputs/basic_fuchsia_tree/lib/x86_64-fuchsia/c++/asan+noexcept/libc++.so b/clang/test/Driver/Inputs/basic_fuchsia_tree/lib/x86_64-fuchsia/c++/asan+noexcept/libc++.so
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/clang/test/Driver/fuchsia.cpp b/clang/test/Driver/fuchsia.cpp
index 823ded4b91544..a5297e76964e4 100644
--- a/clang/test/Driver/fuchsia.cpp
+++ b/clang/test/Driver/fuchsia.cpp
@@ -70,8 +70,9 @@
// RUN: -ccc-install-dir %S/Inputs/basic_fuchsia_tree/bin \
// RUN: -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
// RUN: -fuse-ld=lld 2>&1\
-// RUN: | FileCheck %s -check-prefixes=CHECK-MULTILIB-X86,CHECK-MULTILIB-ASAN-X86
+// RUN: | FileCheck %s -check-prefixes=CHECK-MULTILIB-X86,CHECK-MULTILIB-ASAN-NOEXCEPT-X86
// CHECK-MULTILIB-X86: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]"
// CHECK-MULTILIB-ASAN-X86: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}x86_64-fuchsia{{/|\\\\}}c++{{/|\\\\}}asan"
// CHECK-MULTILIB-NOEXCEPT-X86: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}x86_64-fuchsia{{/|\\\\}}c++{{/|\\\\}}noexcept"
+// CHECK-MULTILIB-ASAN-NOEXCEPT-X86: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}x86_64-fuchsia{{/|\\\\}}c++{{/|\\\\}}asan+noexcept"
// CHECK-MULTILIB-X86: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}x86_64-fuchsia{{/|\\\\}}c++"
From f1d865398b1cf5c082486fe51b52e0b41986640b Mon Sep 17 00:00:00 2001
From: Simon Pilgrim
Date: Sat, 13 Jul 2019 08:08:43 +0000
Subject: [PATCH 032/451] Fix -Wdocumentation warning. NFCI.
llvm-svn: 365995
---
clang/include/clang/DirectoryWatcher/DirectoryWatcher.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h b/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h
index 0bf966bb832ab..e74443e0bc81c 100644
--- a/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h
+++ b/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h
@@ -98,8 +98,7 @@ class DirectoryWatcher {
: Kind(Kind), Filename(Filename) {}
};
- /// Returns nullptr if \param Path doesn't exist.
- /// Returns nullptr if \param Path isn't a directory.
+ /// Returns nullptr if \param Path doesn't exist or isn't a directory.
/// Returns nullptr if OS kernel API told us we can't start watching. In such
/// case it's unclear whether just retrying has any chance to succeeed.
static std::unique_ptr
From 16ac7a5a27c7c3a668c67c776f9230de409bf004 Mon Sep 17 00:00:00 2001
From: Fangrui Song
Date: Sat, 13 Jul 2019 09:23:35 +0000
Subject: [PATCH 033/451] [Object] isNotObjectErrorInvalidFileType: fix
use-after-move
llvm-svn: 365996
---
llvm/lib/Object/Error.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Object/Error.cpp b/llvm/lib/Object/Error.cpp
index f2a009000c58d..ab10d23036a26 100644
--- a/llvm/lib/Object/Error.cpp
+++ b/llvm/lib/Object/Error.cpp
@@ -91,5 +91,5 @@ llvm::Error llvm::object::isNotObjectErrorInvalidFileType(llvm::Error Err) {
return Error(std::move(M));
}))
return Err2;
- return Err;
+ return Error::success();
}
From 327db23b6642499fab917014a4c9934c1649e120 Mon Sep 17 00:00:00 2001
From: Fangrui Song
Date: Sat, 13 Jul 2019 09:28:33 +0000
Subject: [PATCH 034/451] [Object] isNotObjectErrorInvalidFileType: simplify
llvm-svn: 365997
---
llvm/lib/Object/Error.cpp | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Object/Error.cpp b/llvm/lib/Object/Error.cpp
index ab10d23036a26..010c5b42dac25 100644
--- a/llvm/lib/Object/Error.cpp
+++ b/llvm/lib/Object/Error.cpp
@@ -78,18 +78,15 @@ const std::error_category &object::object_category() {
}
llvm::Error llvm::object::isNotObjectErrorInvalidFileType(llvm::Error Err) {
- if (auto Err2 =
- handleErrors(std::move(Err), [](std::unique_ptr M) -> Error {
- // Try to handle 'M'. If successful, return a success value from
- // the handler.
- if (M->convertToErrorCode() == object_error::invalid_file_type)
- return Error::success();
+ return handleErrors(std::move(Err), [](std::unique_ptr M) -> Error {
+ // Try to handle 'M'. If successful, return a success value from
+ // the handler.
+ if (M->convertToErrorCode() == object_error::invalid_file_type)
+ return Error::success();
- // We failed to handle 'M' - return it from the handler.
- // This value will be passed back from catchErrors and
- // wind up in Err2, where it will be returned from this function.
- return Error(std::move(M));
- }))
- return Err2;
- return Error::success();
+ // We failed to handle 'M' - return it from the handler.
+ // This value will be passed back from catchErrors and
+ // wind up in Err2, where it will be returned from this function.
+ return Error(std::move(M));
+ });
}
From 2097f75eabb94c7eafcfba9cbfd6b60f08a4ded6 Mon Sep 17 00:00:00 2001
From: Sanjay Patel
Date: Sat, 13 Jul 2019 12:04:52 +0000
Subject: [PATCH 035/451] [x86] simplify cmov with same true/false operands
llvm-svn: 365998
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 4 ++++
llvm/test/CodeGen/X86/combine-sbb.ll | 3 +--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 6b152fe9d7ac1..e0bcf70248948 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -36783,6 +36783,10 @@ static SDValue combineCMov(SDNode *N, SelectionDAG &DAG,
X86::CondCode CC = (X86::CondCode)N->getConstantOperandVal(2);
SDValue Cond = N->getOperand(3);
+ // cmov X, X, ?, ? --> X
+ if (TrueOp == FalseOp)
+ return TrueOp;
+
// Try to simplify the EFLAGS and condition code operands.
// We can't always do this as FCMOV only supports a subset of X86 cond.
if (SDValue Flags = combineSetCCEFLAGS(Cond, CC, DAG, Subtarget)) {
diff --git a/llvm/test/CodeGen/X86/combine-sbb.ll b/llvm/test/CodeGen/X86/combine-sbb.ll
index f9ac10755aaf0..9e68ab4beb16b 100644
--- a/llvm/test/CodeGen/X86/combine-sbb.ll
+++ b/llvm/test/CodeGen/X86/combine-sbb.ll
@@ -291,9 +291,8 @@ define i32 @PR40483_sub5(i32*, i32) {
;
; X64-LABEL: PR40483_sub5:
; X64: # %bb.0:
-; X64-NEXT: xorl %eax, %eax
; X64-NEXT: subl %esi, (%rdi)
-; X64-NEXT: cmovael %eax, %eax
+; X64-NEXT: xorl %eax, %eax
; X64-NEXT: retq
%3 = load i32, i32* %0, align 8
%4 = tail call { i8, i32 } @llvm.x86.subborrow.32(i8 0, i32 %3, i32 %1)
From 0f6148df23edcd3081f5e761de19edd4f823f16d Mon Sep 17 00:00:00 2001
From: Sanjay Patel
Date: Sat, 13 Jul 2019 12:54:48 +0000
Subject: [PATCH 036/451] [InstCombine] add tests for umin/umax via usub.sat;
NFC
llvm-svn: 365999
---
.../InstCombine/saturating-add-sub.ll | 72 +++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
index 364c80d205f2d..56e10626104cf 100644
--- a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
+++ b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
@@ -1614,3 +1614,75 @@ define i32 @unsigned_sat_constant_using_min_wrong_constant(i32 %x) {
%r = add i32 %s, -42
ret i32 %r
}
+
+define i8 @umax(i8 %a, i8 %b) {
+; CHECK-LABEL: @umax(
+; CHECK-NEXT: [[USUB:%.*]] = tail call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 [[B:%.*]])
+; CHECK-NEXT: [[R:%.*]] = add i8 [[USUB]], [[B]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %usub = tail call i8 @llvm.usub.sat.i8(i8 %a, i8 %b)
+ %r = add i8 %usub, %b
+ ret i8 %r
+}
+
+define <2 x i8> @umax_vec(<2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: @umax_vec(
+; CHECK-NEXT: [[USUB:%.*]] = tail call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]])
+; CHECK-NEXT: [[R:%.*]] = add <2 x i8> [[USUB]], [[B]]
+; CHECK-NEXT: ret <2 x i8> [[R]]
+;
+ %usub = tail call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %a, <2 x i8> %b)
+ %r = add <2 x i8> %usub, %b
+ ret <2 x i8> %r
+}
+
+define i8 @umax_extra_use(i8 %a, i8 %b) {
+; CHECK-LABEL: @umax_extra_use(
+; CHECK-NEXT: [[USUB:%.*]] = tail call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 [[B:%.*]])
+; CHECK-NEXT: call void @use(i8 [[USUB]])
+; CHECK-NEXT: [[R:%.*]] = add i8 [[USUB]], [[B]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %usub = tail call i8 @llvm.usub.sat.i8(i8 %a, i8 %b)
+ call void @use(i8 %usub)
+ %r = add i8 %usub, %b
+ ret i8 %r
+}
+
+define i8 @umin(i8 %a, i8 %b) {
+; CHECK-LABEL: @umin(
+; CHECK-NEXT: [[USUB:%.*]] = tail call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 [[B:%.*]])
+; CHECK-NEXT: [[R:%.*]] = sub i8 [[A]], [[USUB]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %usub = tail call i8 @llvm.usub.sat.i8(i8 %a, i8 %b)
+ %r = sub i8 %a, %usub
+ ret i8 %r
+}
+
+define <2 x i8> @umin_vec(<2 x i8> %a, <2 x i8> %b) {
+; CHECK-LABEL: @umin_vec(
+; CHECK-NEXT: [[USUB:%.*]] = tail call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]])
+; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> [[A]], [[USUB]]
+; CHECK-NEXT: ret <2 x i8> [[R]]
+;
+ %usub = tail call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %a, <2 x i8> %b)
+ %r = sub <2 x i8> %a, %usub
+ ret <2 x i8> %r
+}
+
+define i8 @umin_extra_use(i8 %a, i8 %b) {
+; CHECK-LABEL: @umin_extra_use(
+; CHECK-NEXT: [[USUB:%.*]] = tail call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 [[B:%.*]])
+; CHECK-NEXT: call void @use(i8 [[USUB]])
+; CHECK-NEXT: [[R:%.*]] = sub i8 [[A]], [[USUB]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %usub = tail call i8 @llvm.usub.sat.i8(i8 %a, i8 %b)
+ call void @use(i8 %usub)
+ %r = sub i8 %a, %usub
+ ret i8 %r
+}
+
+declare void @use(i8)
From 22cc1030f6a9afd14cc48ec0b935ebe8678c0c2e Mon Sep 17 00:00:00 2001
From: Sanjay Patel
Date: Sat, 13 Jul 2019 13:16:46 +0000
Subject: [PATCH 037/451] Revert "[InstCombine] add tests for umin/umax via
usub.sat; NFC"
This reverts commit rL365999 / 0f6148df23edcd3081f5e761de19edd4f823f16d.
The tests already exist in this file, and the hoped-for transform
(mentioned in D62871) is invalid because of undef as discussed in
D63060.
llvm-svn: 366000
---
.../InstCombine/saturating-add-sub.ll | 72 -------------------
1 file changed, 72 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
index 56e10626104cf..364c80d205f2d 100644
--- a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
+++ b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
@@ -1614,75 +1614,3 @@ define i32 @unsigned_sat_constant_using_min_wrong_constant(i32 %x) {
%r = add i32 %s, -42
ret i32 %r
}
-
-define i8 @umax(i8 %a, i8 %b) {
-; CHECK-LABEL: @umax(
-; CHECK-NEXT: [[USUB:%.*]] = tail call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 [[B:%.*]])
-; CHECK-NEXT: [[R:%.*]] = add i8 [[USUB]], [[B]]
-; CHECK-NEXT: ret i8 [[R]]
-;
- %usub = tail call i8 @llvm.usub.sat.i8(i8 %a, i8 %b)
- %r = add i8 %usub, %b
- ret i8 %r
-}
-
-define <2 x i8> @umax_vec(<2 x i8> %a, <2 x i8> %b) {
-; CHECK-LABEL: @umax_vec(
-; CHECK-NEXT: [[USUB:%.*]] = tail call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]])
-; CHECK-NEXT: [[R:%.*]] = add <2 x i8> [[USUB]], [[B]]
-; CHECK-NEXT: ret <2 x i8> [[R]]
-;
- %usub = tail call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %a, <2 x i8> %b)
- %r = add <2 x i8> %usub, %b
- ret <2 x i8> %r
-}
-
-define i8 @umax_extra_use(i8 %a, i8 %b) {
-; CHECK-LABEL: @umax_extra_use(
-; CHECK-NEXT: [[USUB:%.*]] = tail call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 [[B:%.*]])
-; CHECK-NEXT: call void @use(i8 [[USUB]])
-; CHECK-NEXT: [[R:%.*]] = add i8 [[USUB]], [[B]]
-; CHECK-NEXT: ret i8 [[R]]
-;
- %usub = tail call i8 @llvm.usub.sat.i8(i8 %a, i8 %b)
- call void @use(i8 %usub)
- %r = add i8 %usub, %b
- ret i8 %r
-}
-
-define i8 @umin(i8 %a, i8 %b) {
-; CHECK-LABEL: @umin(
-; CHECK-NEXT: [[USUB:%.*]] = tail call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 [[B:%.*]])
-; CHECK-NEXT: [[R:%.*]] = sub i8 [[A]], [[USUB]]
-; CHECK-NEXT: ret i8 [[R]]
-;
- %usub = tail call i8 @llvm.usub.sat.i8(i8 %a, i8 %b)
- %r = sub i8 %a, %usub
- ret i8 %r
-}
-
-define <2 x i8> @umin_vec(<2 x i8> %a, <2 x i8> %b) {
-; CHECK-LABEL: @umin_vec(
-; CHECK-NEXT: [[USUB:%.*]] = tail call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[A:%.*]], <2 x i8> [[B:%.*]])
-; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> [[A]], [[USUB]]
-; CHECK-NEXT: ret <2 x i8> [[R]]
-;
- %usub = tail call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %a, <2 x i8> %b)
- %r = sub <2 x i8> %a, %usub
- ret <2 x i8> %r
-}
-
-define i8 @umin_extra_use(i8 %a, i8 %b) {
-; CHECK-LABEL: @umin_extra_use(
-; CHECK-NEXT: [[USUB:%.*]] = tail call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 [[B:%.*]])
-; CHECK-NEXT: call void @use(i8 [[USUB]])
-; CHECK-NEXT: [[R:%.*]] = sub i8 [[A]], [[USUB]]
-; CHECK-NEXT: ret i8 [[R]]
-;
- %usub = tail call i8 @llvm.usub.sat.i8(i8 %a, i8 %b)
- call void @use(i8 %usub)
- %r = sub i8 %a, %usub
- ret i8 %r
-}
-
-declare void @use(i8)
From 2a7f5204602938ae89b0860e9412603d1951d945 Mon Sep 17 00:00:00 2001
From: Thomas Preud'homme
Date: Sat, 13 Jul 2019 13:24:30 +0000
Subject: [PATCH 038/451] FileCheck [7/12]: Arbitrary long numeric expressions
Summary:
This patch is part of a patch series to add support for FileCheck
numeric expressions. This specific patch extend numeric expression to
support an arbitrary number of operands, either variable or literals.
Copyright:
- Linaro (changes up to diff 183612 of revision D55940)
- GraphCore (changes in later versions of revision D55940 and
in new revision created off D55940)
Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar, arichardson, rnk
Subscribers: hiraditya, llvm-commits, probinson, dblaikie, grimar, arichardson, tra, rnk, kristina, hfinkel, rogfer01, JonChesterfield
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60387
llvm-svn: 366001
---
llvm/docs/CommandGuide/FileCheck.rst | 25 +-
llvm/include/llvm/Support/FileCheck.h | 208 ++++++++++------
llvm/lib/Support/FileCheck.cpp | 208 +++++++++-------
llvm/test/FileCheck/line-count.txt | 2 +-
llvm/test/FileCheck/numeric-expression.txt | 20 +-
llvm/test/FileCheck/var-scope.txt | 4 +-
llvm/unittests/Support/FileCheckTest.cpp | 273 ++++++++++++---------
7 files changed, 446 insertions(+), 294 deletions(-)
diff --git a/llvm/docs/CommandGuide/FileCheck.rst b/llvm/docs/CommandGuide/FileCheck.rst
index a424606d4ce0a..0aa2d89fbcf08 100644
--- a/llvm/docs/CommandGuide/FileCheck.rst
+++ b/llvm/docs/CommandGuide/FileCheck.rst
@@ -107,10 +107,12 @@ and from the command line.
Sets a filecheck pattern variable ``VAR`` with value ``VALUE`` that can be
used in ``CHECK:`` lines.
-.. option:: -D#=
+.. option:: -D#=
- Sets a filecheck numeric variable ``NUMVAR`` to ```` that can be used
- in ``CHECK:`` lines.
+ Sets a filecheck numeric variable ``NUMVAR`` to the result of evaluating
+ ```` that can be used in ``CHECK:`` lines. See section
+ ``FileCheck Numeric Variables and Expressions`` for details on the format
+ and meaning of ````.
.. option:: -version
@@ -590,18 +592,15 @@ For example:
would match ``mov r5, 42`` and set ``REG`` to the value ``5``.
-The syntax of a numeric substitution is ``[[#