Empty merge of sc-v2-dev-plus-aosp-without-vendor@8433047
Bug: 226662282
Merged-In: Ica2872d5f5dd6ad85ccecfce263d6335a575362e
Change-Id: Ia6f6883c6d5e56e4109c954b9559a16ecf1841cf
diff --git a/TEST_MAPPING b/TEST_MAPPING
index ad8df10..827a29f 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1187,6 +1187,9 @@
"name": "art-run-test-730-checker-inlining-super[com.google.android.art.apex]"
},
{
+ "name": "art-run-test-731-bounds-check-slow-path[com.google.android.art.apex]"
+ },
+ {
"name": "art-run-test-805-TooDeepClassInstanceOf[com.google.android.art.apex]"
},
{
@@ -2479,6 +2482,9 @@
"name": "art-run-test-730-checker-inlining-super"
},
{
+ "name": "art-run-test-731-bounds-check-slow-path"
+ },
+ {
"name": "art-run-test-805-TooDeepClassInstanceOf"
},
{
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 4025684..8c6b802 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -150,41 +150,62 @@
LocationSummary* locations = instruction_->GetLocations();
CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
__ Bind(GetEntryLabel());
- // We're moving two locations to locations that could overlap, so we need a parallel
- // move resolver.
if (instruction_->CanThrowIntoCatchBlock()) {
// Live registers will be restored in the catch block if caught.
- SaveLiveRegisters(codegen, instruction_->GetLocations());
+ SaveLiveRegisters(codegen, locations);
}
- // Are we using an array length from memory?
- HInstruction* array_length = instruction_->InputAt(1);
+ Location index_loc = locations->InAt(0);
Location length_loc = locations->InAt(1);
InvokeRuntimeCallingConvention calling_convention;
- if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
- // Load the array length into our temporary.
- HArrayLength* length = array_length->AsArrayLength();
- uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(length);
+ Location index_arg = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ Location length_arg = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
+
+ // Are we using an array length from memory?
+ if (!length_loc.IsValid()) {
+ DCHECK(instruction_->InputAt(1)->IsArrayLength());
+ HArrayLength* array_length = instruction_->InputAt(1)->AsArrayLength();
+ DCHECK(array_length->IsEmittedAtUseSite());
+ uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length);
Location array_loc = array_length->GetLocations()->InAt(0);
- Address array_len(array_loc.AsRegister<Register>(), len_offset);
- length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
- // Check for conflicts with index.
- if (length_loc.Equals(locations->InAt(0))) {
- // We know we aren't using parameter 2.
- length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
+ if (!index_loc.Equals(length_arg)) {
+ // The index is not clobbered by loading the length directly to `length_arg`.
+ __ movl(length_arg.AsRegister<Register>(),
+ Address(array_loc.AsRegister<Register>(), len_offset));
+ x86_codegen->Move32(index_arg, index_loc);
+ } else if (!array_loc.Equals(index_arg)) {
+ // The array reference is not clobbered by the index move.
+ x86_codegen->Move32(index_arg, index_loc);
+ __ movl(length_arg.AsRegister<Register>(),
+ Address(array_loc.AsRegister<Register>(), len_offset));
+ } else {
+ // We do not have a temporary we could use, so swap the registers using the
+ // parallel move resolver and replace the array with the length afterwards.
+ codegen->EmitParallelMoves(
+ index_loc,
+ index_arg,
+ DataType::Type::kInt32,
+ array_loc,
+ length_arg,
+ DataType::Type::kReference);
+ __ movl(length_arg.AsRegister<Register>(),
+ Address(length_arg.AsRegister<Register>(), len_offset));
}
- __ movl(length_loc.AsRegister<Register>(), array_len);
- if (mirror::kUseStringCompression && length->IsStringLength()) {
- __ shrl(length_loc.AsRegister<Register>(), Immediate(1));
+ if (mirror::kUseStringCompression && array_length->IsStringLength()) {
+ __ shrl(length_arg.AsRegister<Register>(), Immediate(1));
}
+ } else {
+ // We're moving two locations to locations that could overlap,
+ // so we need a parallel move resolver.
+ codegen->EmitParallelMoves(
+ index_loc,
+ index_arg,
+ DataType::Type::kInt32,
+ length_loc,
+ length_arg,
+ DataType::Type::kInt32);
}
- x86_codegen->EmitParallelMoves(
- locations->InAt(0),
- Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
- DataType::Type::kInt32,
- length_loc,
- Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
- DataType::Type::kInt32);
+
QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
? kQuickThrowStringBounds
: kQuickThrowArrayBounds;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 8c1a533..d919fa7 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -203,39 +203,54 @@
__ Bind(GetEntryLabel());
if (instruction_->CanThrowIntoCatchBlock()) {
// Live registers will be restored in the catch block if caught.
- SaveLiveRegisters(codegen, instruction_->GetLocations());
- }
- // Are we using an array length from memory?
- HInstruction* array_length = instruction_->InputAt(1);
- Location length_loc = locations->InAt(1);
- InvokeRuntimeCallingConvention calling_convention;
- if (array_length->IsArrayLength() && array_length->IsEmittedAtUseSite()) {
- // Load the array length into our temporary.
- HArrayLength* length = array_length->AsArrayLength();
- uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(length);
- Location array_loc = array_length->GetLocations()->InAt(0);
- Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
- length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
- // Check for conflicts with index.
- if (length_loc.Equals(locations->InAt(0))) {
- // We know we aren't using parameter 2.
- length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
- }
- __ movl(length_loc.AsRegister<CpuRegister>(), array_len);
- if (mirror::kUseStringCompression && length->IsStringLength()) {
- __ shrl(length_loc.AsRegister<CpuRegister>(), Immediate(1));
- }
+ SaveLiveRegisters(codegen, locations);
}
- // We're moving two locations to locations that could overlap, so we need a parallel
- // move resolver.
- codegen->EmitParallelMoves(
- locations->InAt(0),
- Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
- DataType::Type::kInt32,
- length_loc,
- Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
- DataType::Type::kInt32);
+ Location index_loc = locations->InAt(0);
+ Location length_loc = locations->InAt(1);
+ InvokeRuntimeCallingConvention calling_convention;
+ Location index_arg = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ Location length_arg = Location::RegisterLocation(calling_convention.GetRegisterAt(1));
+
+ // Are we using an array length from memory?
+ if (!length_loc.IsValid()) {
+ DCHECK(instruction_->InputAt(1)->IsArrayLength());
+ HArrayLength* array_length = instruction_->InputAt(1)->AsArrayLength();
+ DCHECK(array_length->IsEmittedAtUseSite());
+ uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length);
+ Location array_loc = array_length->GetLocations()->InAt(0);
+ Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
+ if (!index_loc.Equals(length_arg)) {
+ // The index is not clobbered by loading the length directly to `length_arg`.
+ __ movl(length_arg.AsRegister<CpuRegister>(), array_len);
+ x86_64_codegen->Move(index_arg, index_loc);
+ } else if (!array_loc.Equals(index_arg)) {
+ // The array reference is not clobbered by the index move.
+ x86_64_codegen->Move(index_arg, index_loc);
+ __ movl(length_arg.AsRegister<CpuRegister>(), array_len);
+ } else {
+ // Load the array length into `TMP`.
+ DCHECK(codegen->IsBlockedCoreRegister(TMP));
+ __ movl(CpuRegister(TMP), array_len);
+ // Single move to CPU register does not clobber `TMP`.
+ x86_64_codegen->Move(index_arg, index_loc);
+ __ movl(length_arg.AsRegister<CpuRegister>(), CpuRegister(TMP));
+ }
+ if (mirror::kUseStringCompression && array_length->IsStringLength()) {
+ __ shrl(length_arg.AsRegister<CpuRegister>(), Immediate(1));
+ }
+ } else {
+ // We're moving two locations to locations that could overlap,
+ // so we need a parallel move resolver.
+ codegen->EmitParallelMoves(
+ index_loc,
+ index_arg,
+ DataType::Type::kInt32,
+ length_loc,
+ length_arg,
+ DataType::Type::kInt32);
+ }
+
QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
? kQuickThrowStringBounds
: kQuickThrowArrayBounds;
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 77dfe68..2d7c208 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -491,9 +491,9 @@
}
bool HLoopOptimization::Run() {
- // Skip if there is no loop or the graph has try-catch/irreducible loops.
+ // Skip if there is no loop or the graph has irreducible loops.
// TODO: make this less of a sledgehammer.
- if (!graph_->HasLoops() || graph_->HasTryCatch() || graph_->HasIrreducibleLoops()) {
+ if (!graph_->HasLoops() || graph_->HasIrreducibleLoops()) {
return false;
}
@@ -502,7 +502,7 @@
loop_allocator_ = &allocator;
// Perform loop optimizations.
- bool didLoopOpt = LocalRun();
+ const bool did_loop_opt = LocalRun();
if (top_loop_ == nullptr) {
graph_->SetHasLoops(false); // no more loops
}
@@ -511,7 +511,7 @@
loop_allocator_ = nullptr;
last_loop_ = top_loop_ = nullptr;
- return didLoopOpt;
+ return did_loop_opt;
}
//
@@ -519,7 +519,6 @@
//
bool HLoopOptimization::LocalRun() {
- bool didLoopOpt = false;
// Build the linear order using the phase-local allocator. This step enables building
// a loop hierarchy that properly reflects the outer-inner and previous-next relation.
ScopedArenaVector<HBasicBlock*> linear_order(loop_allocator_->Adapter(kArenaAllocLinearOrder));
@@ -532,34 +531,37 @@
}
}
+ // TODO(solanes): How can `top_loop_` be null if `graph_->HasLoops()` is true?
+ if (top_loop_ == nullptr) {
+ return false;
+ }
+
// Traverse the loop hierarchy inner-to-outer and optimize. Traversal can use
// temporary data structures using the phase-local allocator. All new HIR
// should use the global allocator.
- if (top_loop_ != nullptr) {
- ScopedArenaSet<HInstruction*> iset(loop_allocator_->Adapter(kArenaAllocLoopOptimization));
- ScopedArenaSafeMap<HInstruction*, HInstruction*> reds(
- std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
- ScopedArenaSet<ArrayReference> refs(loop_allocator_->Adapter(kArenaAllocLoopOptimization));
- ScopedArenaSafeMap<HInstruction*, HInstruction*> map(
- std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
- ScopedArenaSafeMap<HInstruction*, HInstruction*> perm(
- std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
- // Attach.
- iset_ = &iset;
- reductions_ = &reds;
- vector_refs_ = &refs;
- vector_map_ = ↦
- vector_permanent_map_ = &perm;
- // Traverse.
- didLoopOpt = TraverseLoopsInnerToOuter(top_loop_);
- // Detach.
- iset_ = nullptr;
- reductions_ = nullptr;
- vector_refs_ = nullptr;
- vector_map_ = nullptr;
- vector_permanent_map_ = nullptr;
- }
- return didLoopOpt;
+ ScopedArenaSet<HInstruction*> iset(loop_allocator_->Adapter(kArenaAllocLoopOptimization));
+ ScopedArenaSafeMap<HInstruction*, HInstruction*> reds(
+ std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
+ ScopedArenaSet<ArrayReference> refs(loop_allocator_->Adapter(kArenaAllocLoopOptimization));
+ ScopedArenaSafeMap<HInstruction*, HInstruction*> map(
+ std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
+ ScopedArenaSafeMap<HInstruction*, HInstruction*> perm(
+ std::less<HInstruction*>(), loop_allocator_->Adapter(kArenaAllocLoopOptimization));
+ // Attach.
+ iset_ = &iset;
+ reductions_ = &reds;
+ vector_refs_ = &refs;
+ vector_map_ = ↦
+ vector_permanent_map_ = &perm;
+ // Traverse.
+ const bool did_loop_opt = TraverseLoopsInnerToOuter(top_loop_);
+ // Detach.
+ iset_ = nullptr;
+ reductions_ = nullptr;
+ vector_refs_ = nullptr;
+ vector_map_ = nullptr;
+ vector_permanent_map_ = nullptr;
+ return did_loop_opt;
}
void HLoopOptimization::AddLoop(HLoopInformation* loop_info) {
@@ -618,6 +620,18 @@
induction_range_.ReVisit(node->loop_info);
changed = true;
}
+
+ CalculateAndSetTryCatchKind(node);
+ if (node->try_catch_kind == LoopNode::TryCatchKind::kHasTryCatch) {
+ // The current optimizations assume that the loops do not contain try/catches.
+ // TODO(solanes, 227283906): Assess if we can modify them to work with try/catches.
+ continue;
+ }
+
+ DCHECK(node->try_catch_kind == LoopNode::TryCatchKind::kNoTryCatch)
+ << "kind: " << static_cast<int>(node->try_catch_kind)
+ << ". LoopOptimization requires the loops to not have try catches.";
+
// Repeat simplifications in the loop-body until no more changes occur.
// Note that since each simplification consists of eliminating code (without
// introducing new code), this process is always finite.
@@ -635,6 +649,37 @@
return changed;
}
+void HLoopOptimization::CalculateAndSetTryCatchKind(LoopNode* node) {
+ DCHECK(node != nullptr);
+ DCHECK(node->try_catch_kind == LoopNode::TryCatchKind::kUnknown)
+ << "kind: " << static_cast<int>(node->try_catch_kind)
+ << ". SetTryCatchKind should be called only once per LoopNode.";
+
+ // If a inner loop has a try catch, then the outer loop has one too (as it contains `inner`).
+ // Knowing this, we could skip iterating through all of the outer loop's parents with a simple
+ // check.
+ for (LoopNode* inner = node->inner; inner != nullptr; inner = inner->next) {
+ DCHECK(inner->try_catch_kind != LoopNode::TryCatchKind::kUnknown)
+ << "kind: " << static_cast<int>(inner->try_catch_kind)
+ << ". Should have updated the inner loop before the outer loop.";
+
+ if (inner->try_catch_kind == LoopNode::TryCatchKind::kHasTryCatch) {
+ node->try_catch_kind = LoopNode::TryCatchKind::kHasTryCatch;
+ return;
+ }
+ }
+
+ for (HBlocksInLoopIterator it_loop(*node->loop_info); !it_loop.Done(); it_loop.Advance()) {
+ HBasicBlock* block = it_loop.Current();
+ if (block->GetTryCatchInformation() != nullptr) {
+ node->try_catch_kind = LoopNode::TryCatchKind::kHasTryCatch;
+ return;
+ }
+ }
+
+ node->try_catch_kind = LoopNode::TryCatchKind::kNoTryCatch;
+}
+
//
// Optimization.
//
@@ -782,8 +827,6 @@
return TryOptimizeInnerLoopFinite(node) || TryPeelingAndUnrolling(node);
}
-
-
//
// Scalar loop peeling and unrolling: generic part methods.
//
diff --git a/compiler/optimizing/loop_optimization.h b/compiler/optimizing/loop_optimization.h
index 3acd5b1..b178616 100644
--- a/compiler/optimizing/loop_optimization.h
+++ b/compiler/optimizing/loop_optimization.h
@@ -57,12 +57,23 @@
outer(nullptr),
inner(nullptr),
previous(nullptr),
- next(nullptr) {}
+ next(nullptr),
+ try_catch_kind(TryCatchKind::kUnknown) {}
+
+ enum class TryCatchKind {
+ kUnknown,
+ // Either if we have a try catch in the loop, or if the loop is inside of an outer try catch,
+ // we set `kHasTryCatch`.
+ kHasTryCatch,
+ kNoTryCatch
+ };
+
HLoopInformation* loop_info;
LoopNode* outer;
LoopNode* inner;
LoopNode* previous;
LoopNode* next;
+ TryCatchKind try_catch_kind;
};
/*
@@ -131,6 +142,11 @@
// Returns true if loops nested inside current loop (node) have changed.
bool TraverseLoopsInnerToOuter(LoopNode* node);
+ // Calculates `node`'s `try_catch_kind` and sets it to:
+ // 1) kHasTryCatch if it has try catches (or if it's inside of an outer try catch)
+ // 2) kNoTryCatch otherwise.
+ void CalculateAndSetTryCatchKind(LoopNode* node);
+
//
// Optimization.
//
diff --git a/compiler/optimizing/superblock_cloner.cc b/compiler/optimizing/superblock_cloner.cc
index b46d193..a5f919c 100644
--- a/compiler/optimizing/superblock_cloner.cc
+++ b/compiler/optimizing/superblock_cloner.cc
@@ -855,11 +855,20 @@
}
bool SuperblockCloner::IsSubgraphClonable() const {
- // TODO: Support irreducible graphs and graphs with try-catch.
- if (graph_->HasIrreducibleLoops() || graph_->HasTryCatch()) {
+ // TODO: Support irreducible graphs and subgraphs with try-catch.
+ if (graph_->HasIrreducibleLoops()) {
return false;
}
+ for (HBasicBlock* block : graph_->GetReversePostOrder()) {
+ if (!IsInOrigBBSet(block)) {
+ continue;
+ }
+ if (block->GetTryCatchInformation() != nullptr) {
+ return false;
+ }
+ }
+
HInstructionMap live_outs(
std::less<HInstruction*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 51daa30..c0dea85 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -1108,12 +1108,20 @@
size_t Prune() REQUIRES_SHARED(Locks::mutator_lock_) {
ClassTable* class_table =
Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(class_loader_);
+ WriterMutexLock mu(Thread::Current(), class_table->lock_);
for (mirror::Class* klass : classes_to_prune_) {
- std::string storage;
- const char* descriptor = klass->GetDescriptor(&storage);
- bool result = class_table->Remove(descriptor);
- DCHECK(result);
- DCHECK(!class_table->Remove(descriptor)) << descriptor;
+ uint32_t hash = ClassTable::TableSlot::HashDescriptor(klass);
+ DCHECK(!class_table->classes_.empty());
+ ClassTable::ClassSet& last_class_set = class_table->classes_.back();
+ auto it = last_class_set.FindWithHash(ClassTable::TableSlot(klass, hash), hash);
+ DCHECK(it != last_class_set.end());
+ last_class_set.erase(it);
+ DCHECK(std::none_of(class_table->classes_.begin(),
+ class_table->classes_.end(),
+ [klass, hash](ClassTable::ClassSet& class_set) {
+ ClassTable::TableSlot slot(klass, hash);
+ return class_set.FindWithHash(slot, hash) != class_set.end();
+ }));
}
return defined_class_count_;
}
diff --git a/libartbase/base/array_ref.h b/libartbase/base/array_ref.h
index 064e26b..859c2a1 100644
--- a/libartbase/base/array_ref.h
+++ b/libartbase/base/array_ref.h
@@ -65,7 +65,7 @@
template <typename U,
size_t size,
- typename = typename std::enable_if<std::is_same<T, const U>::value>::type>
+ typename = std::enable_if_t<std::is_same_v<T, const U>>>
explicit constexpr ArrayRef(U (&array)[size])
: array_(array), size_(size) {
}
@@ -75,17 +75,14 @@
}
template <typename Vector,
- typename = typename std::enable_if<
- std::is_same<typename Vector::value_type, value_type>::value>::type>
+ typename = std::enable_if_t<std::is_same_v<typename Vector::value_type, value_type>>>
explicit ArrayRef(Vector& v)
: array_(v.data()), size_(v.size()) {
}
template <typename Vector,
- typename = typename std::enable_if<
- std::is_same<
- typename std::add_const<typename Vector::value_type>::type,
- value_type>::value>::type>
+ typename = std::enable_if_t<
+ std::is_same_v<std::add_const_t<typename Vector::value_type>, value_type>>>
explicit ArrayRef(const Vector& v)
: array_(v.data()), size_(v.size()) {
}
@@ -101,7 +98,7 @@
}
template <typename U>
- typename std::enable_if<std::is_same<T, const U>::value, ArrayRef>::type&
+ std::enable_if_t<std::is_same_v<T, const U>, ArrayRef>&
operator=(const ArrayRef<U>& other) {
return *this = ArrayRef(other);
}
diff --git a/libartbase/base/bit_memory_region.h b/libartbase/base/bit_memory_region.h
index cca4217..c5224a5 100644
--- a/libartbase/base/bit_memory_region.h
+++ b/libartbase/base/bit_memory_region.h
@@ -101,8 +101,8 @@
ATTRIBUTE_NO_SANITIZE_ADDRESS // We might touch extra bytes due to the alignment.
ATTRIBUTE_NO_SANITIZE_HWADDRESS // The hwasan uses different attribute.
ALWAYS_INLINE Result LoadBits(size_t bit_offset, size_t bit_length) const {
- static_assert(std::is_integral<Result>::value, "Result must be integral");
- static_assert(std::is_unsigned<Result>::value, "Result must be unsigned");
+ static_assert(std::is_integral_v<Result>, "Result must be integral");
+ static_assert(std::is_unsigned_v<Result>, "Result must be unsigned");
DCHECK(IsAligned<sizeof(Result)>(data_));
DCHECK_LE(bit_offset, bit_size_);
DCHECK_LE(bit_length, bit_size_ - bit_offset);
diff --git a/libartbase/base/bit_string.h b/libartbase/base/bit_string.h
index d995f8d..cce6fe0 100644
--- a/libartbase/base/bit_string.h
+++ b/libartbase/base/bit_string.h
@@ -38,7 +38,7 @@
*/
struct BitStringChar {
using StorageType = uint32_t;
- static_assert(std::is_unsigned<StorageType>::value, "BitStringChar::StorageType must be unsigned");
+ static_assert(std::is_unsigned_v<StorageType>, "BitStringChar::StorageType must be unsigned");
// BitStringChars are always zero-initialized by default. Equivalent to BitStringChar(0,0).
BitStringChar() : data_(0u), bitlength_(0u) { }
diff --git a/libartbase/base/bit_struct.h b/libartbase/base/bit_struct.h
index 4cc222c..599e12a 100644
--- a/libartbase/base/bit_struct.h
+++ b/libartbase/base/bit_struct.h
@@ -112,7 +112,7 @@
size_t kBitWidth,
typename StorageType>
struct BitStructField {
- static_assert(std::is_standard_layout<T>::value, "T must be standard layout");
+ static_assert(std::is_standard_layout_v<T>, "T must be standard layout");
operator T() const {
return Get();
@@ -120,7 +120,7 @@
// Exclude overload when T==StorageType.
template <typename _ = void,
- typename = std::enable_if_t<std::is_same<T, StorageType>::value, _>>
+ typename = std::enable_if_t<std::is_same_v<T, StorageType>, _>>
explicit operator StorageType() const {
return BitFieldExtract(storage_, kBitOffset, kBitWidth);
}
@@ -151,7 +151,7 @@
// Since C++ doesn't allow the type of operator= to change out
// in the subclass, reimplement operator= in each subclass
// manually and call this helper function.
- static_assert(std::is_base_of<BitStructField, T2>::value, "T2 must inherit BitStructField");
+ static_assert(std::is_base_of_v<BitStructField, T2>, "T2 must inherit BitStructField");
what.Set(value);
return what;
}
@@ -172,10 +172,9 @@
private:
using ValueConverter = detail::ValueConverter<T>;
using ConversionType = typename ValueConverter::StorageType;
- using ExtractionType =
- typename std::conditional<std::is_signed_v<ConversionType>,
- std::make_signed_t<StorageType>,
- StorageType>::type;
+ using ExtractionType = std::conditional_t<std::is_signed_v<ConversionType>,
+ std::make_signed_t<StorageType>,
+ StorageType>;
StorageType storage_;
};
diff --git a/libartbase/base/bit_struct_detail.h b/libartbase/base/bit_struct_detail.h
index ad7c0f4..0b891ba 100644
--- a/libartbase/base/bit_struct_detail.h
+++ b/libartbase/base/bit_struct_detail.h
@@ -35,13 +35,12 @@
template <size_t kBitSize>
struct MinimumTypeUnsignedHelper {
using type =
- typename std::conditional<kBitSize == 0, void, // NOLINT [whitespace/operators] [3]
- typename std::conditional<kBitSize <= 8, uint8_t, // NOLINT [whitespace/operators] [3]
- typename std::conditional<kBitSize <= 16, uint16_t, // NOLINT [whitespace/operators] [3]
- typename std::conditional<kBitSize <= 32, uint32_t,
- typename std::conditional<kBitSize <= 64, uint64_t,
- typename std::conditional<kBitSize <= BitSizeOf<uintmax_t>(), uintmax_t,
- void>::type>::type>::type>::type>::type>::type;
+ std::conditional_t<kBitSize == 0, void, // NOLINT [whitespace/operators] [3]
+ std::conditional_t<kBitSize <= 8, uint8_t, // NOLINT [whitespace/operators] [3]
+ std::conditional_t<kBitSize <= 16, uint16_t, // NOLINT [whitespace/operators] [3]
+ std::conditional_t<kBitSize <= 32, uint32_t,
+ std::conditional_t<kBitSize <= 64, uint64_t,
+ std::conditional_t<kBitSize <= BitSizeOf<uintmax_t>(), uintmax_t, void>>>>>>;
};
// Select the smallest [u]intX_t that will fit kBitSize bits.
@@ -51,9 +50,9 @@
using type_unsigned = typename MinimumTypeUnsignedHelper<kBitSize>::type;
using type =
- typename std::conditional</* if */ std::is_signed<T>::value,
- /* then */ typename std::make_signed<type_unsigned>::type,
- /* else */ type_unsigned>::type;
+ std::conditional_t</* if */ std::is_signed_v<T>,
+ /* then */ std::make_signed_t<type_unsigned>,
+ /* else */ type_unsigned>;
};
// Helper for converting to and from T to an integral type.
@@ -119,8 +118,8 @@
template <typename T>
struct HasUnderscoreField {
private:
- using TrueT = std::integral_constant<bool, true>::type;
- using FalseT = std::integral_constant<bool, false>::type;
+ using TrueT = std::bool_constant<true>::type;
+ using FalseT = std::bool_constant<false>::type;
template <typename C>
static constexpr auto Test(void*) -> decltype(std::declval<C>()._, TrueT{});
@@ -140,13 +139,13 @@
// Nominally used by the BITSTRUCT_DEFINE_END macro.
template <typename T>
static constexpr bool ValidateBitStructSize() {
- static_assert(std::is_union<T>::value, "T must be union");
- static_assert(std::is_standard_layout<T>::value, "T must be standard-layout");
+ static_assert(std::is_union_v<T>, "T must be union");
+ static_assert(std::is_standard_layout_v<T>, "T must be standard-layout");
static_assert(HasUnderscoreField<T>::value, "T must have the _ DefineBitStructSize");
const size_t kBitStructSizeOf = BitStructSizeOf<T>();
- static_assert(std::is_same<decltype(GetMemberType(&T::_)),
- DefineBitStructSize<kBitStructSizeOf>>::value,
+ static_assert(std::is_same_v<decltype(GetMemberType(&T::_)),
+ DefineBitStructSize<kBitStructSizeOf>>,
"T::_ must be a DefineBitStructSize of the same size");
const size_t kExpectedSize = (BitStructSizeOf<T>() < kBitsPerByte)
diff --git a/libartbase/base/bit_utils.h b/libartbase/base/bit_utils.h
index 58cc78c..ffaffc3 100644
--- a/libartbase/base/bit_utils.h
+++ b/libartbase/base/bit_utils.h
@@ -30,8 +30,8 @@
// Like sizeof, but count how many bits a type takes. Pass type explicitly.
template <typename T>
constexpr size_t BitSizeOf() {
- static_assert(std::is_integral<T>::value, "T must be integral");
- using unsigned_type = typename std::make_unsigned<T>::type;
+ static_assert(std::is_integral_v<T>, "T must be integral");
+ using unsigned_type = std::make_unsigned_t<T>;
static_assert(sizeof(T) == sizeof(unsigned_type), "Unexpected type size mismatch!");
static_assert(std::numeric_limits<unsigned_type>::radix == 2, "Unexpected radix!");
return std::numeric_limits<unsigned_type>::digits;
@@ -45,8 +45,8 @@
template<typename T>
constexpr int CLZ(T x) {
- static_assert(std::is_integral<T>::value, "T must be integral");
- static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+ static_assert(std::is_integral_v<T>, "T must be integral");
+ static_assert(std::is_unsigned_v<T>, "T must be unsigned");
static_assert(std::numeric_limits<T>::radix == 2, "Unexpected radix!");
static_assert(sizeof(T) == sizeof(uint64_t) || sizeof(T) <= sizeof(uint32_t),
"Unsupported sizeof(T)");
@@ -60,14 +60,14 @@
// Similar to CLZ except that on zero input it returns bitwidth and supports signed integers.
template<typename T>
constexpr int JAVASTYLE_CLZ(T x) {
- static_assert(std::is_integral<T>::value, "T must be integral");
- using unsigned_type = typename std::make_unsigned<T>::type;
+ static_assert(std::is_integral_v<T>, "T must be integral");
+ using unsigned_type = std::make_unsigned_t<T>;
return (x == 0) ? BitSizeOf<T>() : CLZ(static_cast<unsigned_type>(x));
}
template<typename T>
constexpr int CTZ(T x) {
- static_assert(std::is_integral<T>::value, "T must be integral");
+ static_assert(std::is_integral_v<T>, "T must be integral");
// It is not unreasonable to ask for trailing zeros in a negative number. As such, do not check
// that T is an unsigned type.
static_assert(sizeof(T) == sizeof(uint64_t) || sizeof(T) <= sizeof(uint32_t),
@@ -79,8 +79,8 @@
// Similar to CTZ except that on zero input it returns bitwidth and supports signed integers.
template<typename T>
constexpr int JAVASTYLE_CTZ(T x) {
- static_assert(std::is_integral<T>::value, "T must be integral");
- using unsigned_type = typename std::make_unsigned<T>::type;
+ static_assert(std::is_integral_v<T>, "T must be integral");
+ using unsigned_type = std::make_unsigned_t<T>;
return (x == 0) ? BitSizeOf<T>() : CTZ(static_cast<unsigned_type>(x));
}
@@ -105,8 +105,8 @@
// Find the bit position of the most significant bit (0-based), or -1 if there were no bits set.
template <typename T>
constexpr ssize_t MostSignificantBit(T value) {
- static_assert(std::is_integral<T>::value, "T must be integral");
- static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+ static_assert(std::is_integral_v<T>, "T must be integral");
+ static_assert(std::is_unsigned_v<T>, "T must be unsigned");
static_assert(std::numeric_limits<T>::radix == 2, "Unexpected radix!");
return (value == 0) ? -1 : std::numeric_limits<T>::digits - 1 - CLZ(value);
}
@@ -114,8 +114,8 @@
// Find the bit position of the least significant bit (0-based), or -1 if there were no bits set.
template <typename T>
constexpr ssize_t LeastSignificantBit(T value) {
- static_assert(std::is_integral<T>::value, "T must be integral");
- static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+ static_assert(std::is_integral_v<T>, "T must be integral");
+ static_assert(std::is_unsigned_v<T>, "T must be unsigned");
return (value == 0) ? -1 : CTZ(value);
}
@@ -127,8 +127,8 @@
template <typename T>
constexpr T RoundUpToPowerOfTwo(T x) {
- static_assert(std::is_integral<T>::value, "T must be integral");
- static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+ static_assert(std::is_integral_v<T>, "T must be integral");
+ static_assert(std::is_unsigned_v<T>, "T must be unsigned");
// NOTE: Undefined if x > (1 << (std::numeric_limits<T>::digits - 1)).
return (x < 2u) ? x : static_cast<T>(1u) << (std::numeric_limits<T>::digits - CLZ(x - 1u));
}
@@ -136,21 +136,21 @@
// Return highest possible N - a power of two - such that val >= N.
template <typename T>
constexpr T TruncToPowerOfTwo(T val) {
- static_assert(std::is_integral<T>::value, "T must be integral");
- static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+ static_assert(std::is_integral_v<T>, "T must be integral");
+ static_assert(std::is_unsigned_v<T>, "T must be unsigned");
return (val != 0) ? static_cast<T>(1u) << (BitSizeOf<T>() - CLZ(val) - 1u) : 0;
}
template<typename T>
constexpr bool IsPowerOfTwo(T x) {
- static_assert(std::is_integral<T>::value, "T must be integral");
+ static_assert(std::is_integral_v<T>, "T must be integral");
// TODO: assert unsigned. There is currently many uses with signed values.
return (x & (x - 1)) == 0;
}
template<typename T>
constexpr int WhichPowerOf2(T x) {
- static_assert(std::is_integral<T>::value, "T must be integral");
+ static_assert(std::is_integral_v<T>, "T must be integral");
// TODO: assert unsigned. There is currently many uses with signed values.
DCHECK((x != 0) && IsPowerOfTwo(x));
return CTZ(x);
@@ -168,10 +168,10 @@
}
template<typename T>
-constexpr T RoundUp(T x, typename std::remove_reference<T>::type n) WARN_UNUSED;
+constexpr T RoundUp(T x, std::remove_reference_t<T> n) WARN_UNUSED;
template<typename T>
-constexpr T RoundUp(T x, typename std::remove_reference<T>::type n) {
+constexpr T RoundUp(T x, std::remove_reference_t<T> n) {
return RoundDown(x + n - 1, n);
}
@@ -265,7 +265,7 @@
constexpr bool IsInt(T value) {
static_assert(kBits > 0, "kBits cannot be zero.");
static_assert(kBits <= BitSizeOf<T>(), "kBits must be <= max.");
- static_assert(std::is_signed<T>::value, "Needs a signed type.");
+ static_assert(std::is_signed_v<T>, "Needs a signed type.");
// Corner case for "use all bits." Can't use the limits, as they would overflow, but it is
// trivially true.
return (kBits == BitSizeOf<T>()) ?
@@ -277,12 +277,12 @@
constexpr bool IsUint(T value) {
static_assert(kBits > 0, "kBits cannot be zero.");
static_assert(kBits <= BitSizeOf<T>(), "kBits must be <= max.");
- static_assert(std::is_integral<T>::value, "Needs an integral type.");
+ static_assert(std::is_integral_v<T>, "Needs an integral type.");
// Corner case for "use all bits." Can't use the limits, as they would overflow, but it is
// trivially true.
// NOTE: To avoid triggering assertion in GetIntLimit(kBits+1) if kBits+1==BitSizeOf<T>(),
// use GetIntLimit(kBits)*2u. The unsigned arithmetic works well for us if it overflows.
- using unsigned_type = typename std::make_unsigned<T>::type;
+ using unsigned_type = std::make_unsigned_t<T>;
return (0 <= value) &&
(kBits == BitSizeOf<T>() ||
(static_cast<unsigned_type>(value) <= GetIntLimit<unsigned_type>(kBits) * 2u - 1u));
@@ -291,8 +291,8 @@
template <size_t kBits, typename T>
constexpr bool IsAbsoluteUint(T value) {
static_assert(kBits <= BitSizeOf<T>(), "kBits must be <= max.");
- static_assert(std::is_integral<T>::value, "Needs an integral type.");
- using unsigned_type = typename std::make_unsigned<T>::type;
+ static_assert(std::is_integral_v<T>, "Needs an integral type.");
+ using unsigned_type = std::make_unsigned_t<T>;
return (kBits == BitSizeOf<T>())
? true
: IsUint<kBits>(value < 0
@@ -303,23 +303,23 @@
// Generate maximum/minimum values for signed/unsigned n-bit integers
template <typename T>
constexpr T MaxInt(size_t bits) {
- DCHECK(std::is_unsigned<T>::value || bits > 0u) << "bits cannot be zero for signed.";
+ DCHECK(std::is_unsigned_v<T> || bits > 0u) << "bits cannot be zero for signed.";
DCHECK_LE(bits, BitSizeOf<T>());
- using unsigned_type = typename std::make_unsigned<T>::type;
+ using unsigned_type = std::make_unsigned_t<T>;
return bits == BitSizeOf<T>()
? std::numeric_limits<T>::max()
- : std::is_signed<T>::value
+ : std::is_signed_v<T>
? ((bits == 1u) ? 0 : static_cast<T>(MaxInt<unsigned_type>(bits - 1)))
: static_cast<T>(UINT64_C(1) << bits) - static_cast<T>(1);
}
template <typename T>
constexpr T MinInt(size_t bits) {
- DCHECK(std::is_unsigned<T>::value || bits > 0) << "bits cannot be zero for signed.";
+ DCHECK(std::is_unsigned_v<T> || bits > 0) << "bits cannot be zero for signed.";
DCHECK_LE(bits, BitSizeOf<T>());
return bits == BitSizeOf<T>()
? std::numeric_limits<T>::min()
- : std::is_signed<T>::value
+ : std::is_signed_v<T>
? ((bits == 1u) ? -1 : static_cast<T>(-1) - MaxInt<T>(bits))
: static_cast<T>(0);
}
@@ -334,7 +334,7 @@
// Returns value with bit set in hightest one-bit position or 0 if 0. (java.lang.X.highestOneBit).
template <typename T>
inline static T HighestOneBitValue(T opnd) {
- using unsigned_type = typename std::make_unsigned<T>::type;
+ using unsigned_type = std::make_unsigned_t<T>;
T res;
if (opnd == 0) {
res = 0;
@@ -351,7 +351,7 @@
int mask = BitSizeOf<T>() - 1;
int unsigned_right_shift = left ? (-distance & mask) : (distance & mask);
int signed_left_shift = left ? (distance & mask) : (-distance & mask);
- using unsigned_type = typename std::make_unsigned<T>::type;
+ using unsigned_type = std::make_unsigned_t<T>;
return (static_cast<unsigned_type>(opnd) >> unsigned_right_shift) | (opnd << signed_left_shift);
}
@@ -485,7 +485,7 @@
const T bitfield_unsigned =
static_cast<T>((val >> lsb) & MaskLeastSignificant<T>(width));
- if (std::is_signed<T>::value) {
+ if (std::is_signed_v<T>) {
// Perform sign extension
if (width == 0) { // Avoid underflow.
return static_cast<T>(0);
diff --git a/libartbase/base/bit_utils_iterator.h b/libartbase/base/bit_utils_iterator.h
index 4975ebf..bfcff86 100644
--- a/libartbase/base/bit_utils_iterator.h
+++ b/libartbase/base/bit_utils_iterator.h
@@ -34,8 +34,8 @@
template <typename T, typename Iter>
class BitIteratorBase
: public std::iterator<std::forward_iterator_tag, uint32_t, ptrdiff_t, void, void> {
- static_assert(std::is_integral<T>::value, "T must be integral");
- static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+ static_assert(std::is_integral_v<T>, "T must be integral");
+ static_assert(std::is_unsigned_v<T>, "T must be unsigned");
static_assert(sizeof(T) == sizeof(uint32_t) || sizeof(T) == sizeof(uint64_t), "Unsupported size");
diff --git a/libartbase/base/casts.h b/libartbase/base/casts.h
index cedd624..c88f589 100644
--- a/libartbase/base/casts.h
+++ b/libartbase/base/casts.h
@@ -71,7 +71,7 @@
template<typename To, typename From> // use like this: down_cast<T*>(foo);
inline To down_cast(From* f) { // so we only accept pointers
- static_assert(std::is_base_of<From, typename std::remove_pointer<To>::type>::value,
+ static_assert(std::is_base_of_v<From, std::remove_pointer_t<To>>,
"down_cast unsafe as To is not a subtype of From");
return static_cast<To>(f);
@@ -79,7 +79,7 @@
template<typename To, typename From> // use like this: down_cast<T&>(foo);
inline To down_cast(From& f) { // so we only accept references
- static_assert(std::is_base_of<From, typename std::remove_reference<To>::type>::value,
+ static_assert(std::is_base_of_v<From, std::remove_reference_t<To>>,
"down_cast unsafe as To is not a subtype of From");
return static_cast<To>(f);
@@ -121,24 +121,22 @@
template <typename Dest, typename Source>
constexpr
-typename std::enable_if<!std::is_enum<Source>::value, Dest>::type
-enum_cast(Source value) {
- return static_cast<Dest>(
- dchecked_integral_cast<typename std::underlying_type<Dest>::type>(value));
+std::enable_if_t<!std::is_enum_v<Source>, Dest> enum_cast(Source value) {
+ return static_cast<Dest>(dchecked_integral_cast<std::underlying_type_t<Dest>>(value));
}
template <typename Dest = void, typename Source>
constexpr
-typename std::enable_if<std::is_enum<Source>::value,
- typename std::conditional<std::is_same<Dest, void>::value,
- std::underlying_type<Source>,
- Identity<Dest>>::type>::type::type
+typename std::enable_if_t<std::is_enum_v<Source>,
+ std::conditional_t<std::is_same_v<Dest, void>,
+ std::underlying_type<Source>,
+ Identity<Dest>>>::type
enum_cast(Source value) {
- using return_type = typename std::conditional<std::is_same<Dest, void>::value,
- std::underlying_type<Source>,
- Identity<Dest>>::type::type;
+ using return_type = typename std::conditional_t<std::is_same_v<Dest, void>,
+ std::underlying_type<Source>,
+ Identity<Dest>>::type;
return dchecked_integral_cast<return_type>(
- static_cast<typename std::underlying_type<Source>::type>(value));
+ static_cast<std::underlying_type_t<Source>>(value));
}
// A version of reinterpret_cast<>() between pointers and int64_t/uint64_t
@@ -147,9 +145,9 @@
template <typename Dest, typename Source>
inline Dest reinterpret_cast64(Source source) {
// This is the overload for casting from int64_t/uint64_t to a pointer.
- static_assert(std::is_same<Source, int64_t>::value || std::is_same<Source, uint64_t>::value,
+ static_assert(std::is_same_v<Source, int64_t> || std::is_same_v<Source, uint64_t>,
"Source must be int64_t or uint64_t.");
- static_assert(std::is_pointer<Dest>::value, "Dest must be a pointer.");
+ static_assert(std::is_pointer_v<Dest>, "Dest must be a pointer.");
// Check that we don't lose any non-0 bits here.
DCHECK_EQ(static_cast<Source>(static_cast<uintptr_t>(source)), source);
return reinterpret_cast<Dest>(static_cast<uintptr_t>(source));
@@ -158,7 +156,7 @@
template <typename Dest, typename Source>
inline Dest reinterpret_cast64(Source* ptr) {
// This is the overload for casting from a pointer to int64_t/uint64_t.
- static_assert(std::is_same<Dest, int64_t>::value || std::is_same<Dest, uint64_t>::value,
+ static_assert(std::is_same_v<Dest, int64_t> || std::is_same_v<Dest, uint64_t>,
"Dest must be int64_t or uint64_t.");
static_assert(sizeof(uintptr_t) <= sizeof(Dest), "Expecting at most 64-bit pointers.");
return static_cast<Dest>(reinterpret_cast<uintptr_t>(ptr));
@@ -170,9 +168,9 @@
template <typename Dest, typename Source>
inline Dest reinterpret_cast32(Source source) {
// This is the overload for casting from int32_t/uint32_t to a pointer.
- static_assert(std::is_same<Source, int32_t>::value || std::is_same<Source, uint32_t>::value,
+ static_assert(std::is_same_v<Source, int32_t> || std::is_same_v<Source, uint32_t>,
"Source must be int32_t or uint32_t.");
- static_assert(std::is_pointer<Dest>::value, "Dest must be a pointer.");
+ static_assert(std::is_pointer_v<Dest>, "Dest must be a pointer.");
// Check that we don't lose any non-0 bits here.
static_assert(sizeof(uintptr_t) >= sizeof(Source), "Expecting at least 32-bit pointers.");
return reinterpret_cast<Dest>(static_cast<uintptr_t>(static_cast<uint32_t>(source)));
@@ -181,7 +179,7 @@
template <typename Dest, typename Source>
inline Dest reinterpret_cast32(Source* ptr) {
// This is the overload for casting from a pointer to int32_t/uint32_t.
- static_assert(std::is_same<Dest, int32_t>::value || std::is_same<Dest, uint32_t>::value,
+ static_assert(std::is_same_v<Dest, int32_t> || std::is_same_v<Dest, uint32_t>,
"Dest must be int32_t or uint32_t.");
static_assert(sizeof(uintptr_t) >= sizeof(Dest), "Expecting at least 32-bit pointers.");
return static_cast<Dest>(dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(ptr)));
diff --git a/libartbase/base/dchecked_vector.h b/libartbase/base/dchecked_vector.h
index 66e9638..ecb4d2a 100644
--- a/libartbase/base/dchecked_vector.h
+++ b/libartbase/base/dchecked_vector.h
@@ -37,7 +37,7 @@
class dchecked_vector : private std::vector<T, Alloc> {
private:
// std::vector<> has a slightly different specialization for bool. We don't provide that.
- static_assert(!std::is_same<T, bool>::value, "Not implemented for bool.");
+ static_assert(!std::is_same_v<T, bool>, "Not implemented for bool.");
using Base = std::vector<T, Alloc>;
public:
diff --git a/libartbase/base/hash_set.h b/libartbase/base/hash_set.h
index 7ed8c61..c4af1b6 100644
--- a/libartbase/base/hash_set.h
+++ b/libartbase/base/hash_set.h
@@ -50,9 +50,9 @@
// Conversion from iterator to const_iterator.
template <class OtherElem,
class OtherHashSetType,
- typename = typename std::enable_if<
- std::is_same<Elem, const OtherElem>::value &&
- std::is_same<HashSetType, const OtherHashSetType>::value>::type>
+ typename = std::enable_if_t<
+ std::is_same_v<Elem, const OtherElem> &&
+ std::is_same_v<HashSetType, const OtherHashSetType>>>
HashSetIterator(const HashSetIterator<OtherElem, OtherHashSetType>& other)
: index_(other.index_), hash_set_(other.hash_set_) {}
@@ -102,10 +102,10 @@
bool operator==(const HashSetIterator<Elem1, HashSetType1>& lhs,
const HashSetIterator<Elem2, HashSetType2>& rhs) {
static_assert(
- std::is_convertible<HashSetIterator<Elem1, HashSetType1>,
- HashSetIterator<Elem2, HashSetType2>>::value ||
- std::is_convertible<HashSetIterator<Elem2, HashSetType2>,
- HashSetIterator<Elem1, HashSetType1>>::value, "Bad iterator types.");
+ std::is_convertible_v<HashSetIterator<Elem1, HashSetType1>,
+ HashSetIterator<Elem2, HashSetType2>> ||
+ std::is_convertible_v<HashSetIterator<Elem2, HashSetType2>,
+ HashSetIterator<Elem1, HashSetType1>>, "Bad iterator types.");
DCHECK_EQ(lhs.hash_set_, rhs.hash_set_);
return lhs.index_ == rhs.index_;
}
@@ -140,9 +140,7 @@
};
template <class T>
-using DefaultHashFn = typename std::conditional<std::is_same<T, std::string>::value,
- DataHash,
- std::hash<T>>::type;
+using DefaultHashFn = std::conditional_t<std::is_same_v<T, std::string>, DataHash, std::hash<T>>;
struct DefaultStringEquals {
// Allow comparison with anything that can be compared to std::string,
@@ -154,9 +152,8 @@
};
template <class T>
-using DefaultPred = typename std::conditional<std::is_same<T, std::string>::value,
- DefaultStringEquals,
- std::equal_to<T>>::type;
+using DefaultPred =
+ std::conditional_t<std::is_same_v<T, std::string>, DefaultStringEquals, std::equal_to<T>>;
// Low memory version of a hash set, uses less memory than std::unordered_multiset since elements
// aren't boxed. Uses linear probing to resolve collisions.
@@ -509,7 +506,7 @@
return InsertWithHash(std::move(element), hashfn_(element));
}
- template <typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type>
+ template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, T>>>
std::pair<iterator, bool> InsertWithHash(U&& element, size_t hash) {
DCHECK_EQ(hash, hashfn_(element));
if (num_elements_ >= elements_until_expand_) {
@@ -537,7 +534,7 @@
return PutWithHash(std::move(element), hashfn_(element));
}
- template <typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type>
+ template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, T>>>
void PutWithHash(U&& element, size_t hash) {
DCHECK_EQ(hash, hashfn_(element));
if (num_elements_ >= elements_until_expand_) {
diff --git a/libartbase/base/intrusive_forward_list.h b/libartbase/base/intrusive_forward_list.h
index 29db64d..2e66f3e 100644
--- a/libartbase/base/intrusive_forward_list.h
+++ b/libartbase/base/intrusive_forward_list.h
@@ -55,8 +55,7 @@
class IntrusiveForwardListBaseHookTraits;
template <typename T,
- typename HookTraits =
- IntrusiveForwardListBaseHookTraits<typename std::remove_const<T>::type>>
+ typename HookTraits = IntrusiveForwardListBaseHookTraits<std::remove_const_t<T>>>
class IntrusiveForwardList;
template <typename T, typename HookTraits>
@@ -69,7 +68,7 @@
// Conversion from iterator to const_iterator.
template <typename OtherT,
- typename = typename std::enable_if<std::is_same<T, const OtherT>::value>::type>
+ typename = std::enable_if_t<std::is_same_v<T, const OtherT>>>
IntrusiveForwardListIterator(const IntrusiveForwardListIterator<OtherT, HookTraits>& src) // NOLINT, implicit
: hook_(src.hook_) { }
@@ -106,20 +105,20 @@
friend class IntrusiveForwardList;
template <typename OtherT1, typename OtherT2, typename OtherTraits>
- friend typename std::enable_if<std::is_same<const OtherT1, const OtherT2>::value, bool>::type
+ friend std::enable_if_t<std::is_same_v<const OtherT1, const OtherT2>, bool>
operator==(const IntrusiveForwardListIterator<OtherT1, OtherTraits>& lhs,
const IntrusiveForwardListIterator<OtherT2, OtherTraits>& rhs);
};
template <typename T, typename OtherT, typename HookTraits>
-typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type operator==(
+std::enable_if_t<std::is_same_v<const T, const OtherT>, bool> operator==(
const IntrusiveForwardListIterator<T, HookTraits>& lhs,
const IntrusiveForwardListIterator<OtherT, HookTraits>& rhs) {
return lhs.hook_ == rhs.hook_;
}
template <typename T, typename OtherT, typename HookTraits>
-typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type operator!=(
+std::enable_if_t<std::is_same_v<const T, const OtherT>, bool> operator!=(
const IntrusiveForwardListIterator<T, HookTraits>& lhs,
const IntrusiveForwardListIterator<OtherT, HookTraits>& rhs) {
return !(lhs == rhs);
diff --git a/libartbase/base/intrusive_forward_list_test.cc b/libartbase/base/intrusive_forward_list_test.cc
index e97c304..595210b 100644
--- a/libartbase/base/intrusive_forward_list_test.cc
+++ b/libartbase/base/intrusive_forward_list_test.cc
@@ -731,7 +731,7 @@
ModifyValue<IFLTestValueList>();
// Does not compile with ConstIFLTestValueList because LHS of the assignment is const.
// ModifyValue<ConstIFLTestValueList>();
- static_assert(std::is_const<ConstIFLTestValueList::iterator::value_type>::value, "Const check.");
+ static_assert(std::is_const_v<ConstIFLTestValueList::iterator::value_type>);
ModifyValue<IFLTestValue2List>();
}
diff --git a/libartbase/base/leb128.h b/libartbase/base/leb128.h
index b866d37..4f0f975 100644
--- a/libartbase/base/leb128.h
+++ b/libartbase/base/leb128.h
@@ -216,7 +216,7 @@
// (2) there is another Leb128 value before this one.
template <typename T>
static inline T* ReverseSearchUnsignedLeb128(T* end_ptr) {
- static_assert(std::is_same<typename std::remove_const<T>::type, uint8_t>::value,
+ static_assert(std::is_same_v<std::remove_const_t<T>, uint8_t>,
"T must be a uint8_t");
T* ptr = end_ptr;
@@ -257,7 +257,7 @@
template <typename Vector>
static inline void EncodeUnsignedLeb128(Vector* dest, uint32_t value) {
- static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
+ static_assert(std::is_same_v<typename Vector::value_type, uint8_t>, "Invalid value type");
uint8_t out = value & 0x7f;
value >>= 7;
while (value != 0) {
@@ -296,7 +296,7 @@
template<typename Vector>
static inline void EncodeSignedLeb128(Vector* dest, int32_t value) {
- static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
+ static_assert(std::is_same_v<typename Vector::value_type, uint8_t>, "Invalid value type");
uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
uint8_t out = value & 0x7f;
while (extra_bits != 0u) {
@@ -311,7 +311,7 @@
// An encoder that pushes int32_t/uint32_t data onto the given std::vector.
template <typename Vector = std::vector<uint8_t>>
class Leb128Encoder {
- static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
+ static_assert(std::is_same_v<typename Vector::value_type, uint8_t>, "Invalid value type");
public:
explicit Leb128Encoder(Vector* data) : data_(data) {
@@ -359,7 +359,7 @@
template <typename Vector = std::vector<uint8_t>>
class Leb128EncodingVector final : private Vector,
public Leb128Encoder<Vector> {
- static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
+ static_assert(std::is_same_v<typename Vector::value_type, uint8_t>, "Invalid value type");
public:
Leb128EncodingVector() : Leb128Encoder<Vector>(this) { }
diff --git a/libartbase/base/safe_map.h b/libartbase/base/safe_map.h
index 0d7a8c1..7ae85d4 100644
--- a/libartbase/base/safe_map.h
+++ b/libartbase/base/safe_map.h
@@ -149,7 +149,7 @@
template <typename CreateFn>
V& GetOrCreate(const K& k, CreateFn create) {
- static_assert(std::is_same<V, typename std::result_of<CreateFn()>::type>::value,
+ static_assert(std::is_same_v<V, std::result_of_t<CreateFn()>>,
"Argument `create` should return a value of type V.");
auto lb = lower_bound(k);
if (lb != end() && !key_comp()(k, lb->first)) {
diff --git a/libartbase/base/scoped_arena_containers.h b/libartbase/base/scoped_arena_containers.h
index 882fdcc..5f0cfe6 100644
--- a/libartbase/base/scoped_arena_containers.h
+++ b/libartbase/base/scoped_arena_containers.h
@@ -274,7 +274,7 @@
class ArenaDelete<T[]> {
public:
void operator()(T* ptr ATTRIBUTE_UNUSED) const {
- static_assert(std::is_trivially_destructible<T>::value,
+ static_assert(std::is_trivially_destructible_v<T>,
"ArenaUniquePtr does not support non-trivially-destructible arrays.");
// TODO: Implement debug checks, and MEMORY_TOOL support.
}
diff --git a/libartbase/base/stl_util.h b/libartbase/base/stl_util.h
index dfe994e..0ae4fd2 100644
--- a/libartbase/base/stl_util.h
+++ b/libartbase/base/stl_util.h
@@ -290,7 +290,7 @@
template <typename Val>
struct NonNullFilter {
public:
- static_assert(std::is_pointer<Val>::value, "Must be pointer type!");
+ static_assert(std::is_pointer_v<Val>, "Must be pointer type!");
constexpr bool operator()(Val v) const {
return v != nullptr;
}
diff --git a/libartbase/base/transform_array_ref.h b/libartbase/base/transform_array_ref.h
index 2f56e9b..9413b22 100644
--- a/libartbase/base/transform_array_ref.h
+++ b/libartbase/base/transform_array_ref.h
@@ -36,7 +36,7 @@
using FallbackConstIter = std::iterator<std::random_access_iterator_tag, void, void, void, void>;
using PreferredConstIter =
TransformIterator<typename ArrayRef<BaseType>::const_iterator, Function>;
- template <typename F, typename = typename std::result_of<F(const BaseType&)>::type>
+ template <typename F, typename = std::result_of_t<F(const BaseType&)>>
static PreferredConstIter ConstIterHelper(int&);
template <typename F>
static FallbackConstIter ConstIterHelper(const int&);
@@ -50,15 +50,12 @@
using pointer = typename Iter::pointer;
using const_pointer = typename ConstIter::pointer;
using iterator = Iter;
- using const_iterator = typename std::conditional<
- std::is_same<ConstIter, FallbackConstIter>::value,
- void,
- ConstIter>::type;
+ using const_iterator =
+ std::conditional_t<std::is_same_v<ConstIter, FallbackConstIter>, void, ConstIter>;
using reverse_iterator = std::reverse_iterator<Iter>;
- using const_reverse_iterator = typename std::conditional<
- std::is_same<ConstIter, FallbackConstIter>::value,
- void,
- std::reverse_iterator<ConstIter>>::type;
+ using const_reverse_iterator = std::conditional_t<std::is_same_v<ConstIter, FallbackConstIter>,
+ void,
+ std::reverse_iterator<ConstIter>>;
using difference_type = typename ArrayRef<BaseType>::difference_type;
using size_type = typename ArrayRef<BaseType>::size_type;
@@ -71,7 +68,7 @@
: data_(base, fn) { }
template <typename OtherBT,
- typename = typename std::enable_if<std::is_same<BaseType, const OtherBT>::value>::type>
+ typename = std::enable_if_t<std::is_same_v<BaseType, const OtherBT>>>
TransformArrayRef(const TransformArrayRef<OtherBT, Function>& other)
: TransformArrayRef(other.base(), other.GetFunction()) { }
@@ -80,7 +77,7 @@
TransformArrayRef& operator=(const TransformArrayRef& other) = default;
template <typename OtherBT,
- typename = typename std::enable_if<std::is_same<BaseType, const OtherBT>::value>::type>
+ typename = std::enable_if_t<std::is_same_v<BaseType, const OtherBT>>>
TransformArrayRef& operator=(const TransformArrayRef<OtherBT, Function>& other) {
return *this = TransformArrayRef(other.base(), other.GetFunction());
}
diff --git a/libartbase/base/transform_array_ref_test.cc b/libartbase/base/transform_array_ref_test.cc
index 896209b..4ac6978 100644
--- a/libartbase/base/transform_array_ref_test.cc
+++ b/libartbase/base/transform_array_ref_test.cc
@@ -44,12 +44,11 @@
auto taref = MakeTransformArrayRef(input, add1);
using TarefIter = decltype(taref)::iterator;
using ConstTarefIter = decltype(taref)::const_iterator;
- static_assert(std::is_same<int, decltype(taref)::value_type>::value, "value_type");
- static_assert(std::is_same<TarefIter, decltype(taref)::pointer>::value, "pointer");
- static_assert(std::is_same<int, decltype(taref)::reference>::value, "reference");
- static_assert(std::is_same<ConstTarefIter, decltype(taref)::const_pointer>::value,
- "const_pointer");
- static_assert(std::is_same<int, decltype(taref)::const_reference>::value, "const_reference");
+ static_assert(std::is_same_v<int, decltype(taref)::value_type>);
+ static_assert(std::is_same_v<TarefIter, decltype(taref)::pointer>);
+ static_assert(std::is_same_v<int, decltype(taref)::reference>);
+ static_assert(std::is_same_v<ConstTarefIter, decltype(taref)::const_pointer>);
+ static_assert(std::is_same_v<int, decltype(taref)::const_reference>);
std::copy(taref.begin(), taref.end(), std::back_inserter(output));
ASSERT_EQ(std::vector<int>({ 8, 7, 5, 1 }), output);
@@ -84,12 +83,12 @@
auto taref = MakeTransformArrayRef(input, sub1);
using TarefIter = decltype(taref)::iterator;
- static_assert(std::is_same<void, decltype(taref)::const_iterator>::value, "const_iterator");
- static_assert(std::is_same<int, decltype(taref)::value_type>::value, "value_type");
- static_assert(std::is_same<TarefIter, decltype(taref)::pointer>::value, "pointer");
- static_assert(std::is_same<int, decltype(taref)::reference>::value, "reference");
- static_assert(std::is_same<void, decltype(taref)::const_pointer>::value, "const_pointer");
- static_assert(std::is_same<void, decltype(taref)::const_reference>::value, "const_reference");
+ static_assert(std::is_same_v<void, decltype(taref)::const_iterator>);
+ static_assert(std::is_same_v<int, decltype(taref)::value_type>);
+ static_assert(std::is_same_v<TarefIter, decltype(taref)::pointer>);
+ static_assert(std::is_same_v<int, decltype(taref)::reference>);
+ static_assert(std::is_same_v<void, decltype(taref)::const_pointer>);
+ static_assert(std::is_same_v<void, decltype(taref)::const_reference>);
std::copy(taref.begin(), taref.end(), std::back_inserter(output));
ASSERT_EQ(std::vector<int>({ 3, 3, 4, 6, 9 }), output);
@@ -119,12 +118,11 @@
std::vector<int> output;
auto taref = MakeTransformArrayRef(input, ref);
- static_assert(std::is_same<int, decltype(taref)::value_type>::value, "value_type");
- static_assert(std::is_same<int*, decltype(taref)::pointer>::value, "pointer");
- static_assert(std::is_same<int&, decltype(taref)::reference>::value, "reference");
- static_assert(std::is_same<const int*, decltype(taref)::const_pointer>::value, "const_pointer");
- static_assert(std::is_same<const int&, decltype(taref)::const_reference>::value,
- "const_reference");
+ static_assert(std::is_same_v<int, decltype(taref)::value_type>);
+ static_assert(std::is_same_v<int*, decltype(taref)::pointer>);
+ static_assert(std::is_same_v<int&, decltype(taref)::reference>);
+ static_assert(std::is_same_v<const int*, decltype(taref)::const_pointer>);
+ static_assert(std::is_same_v<const int&, decltype(taref)::const_reference>);
std::copy(taref.begin(), taref.end(), std::back_inserter(output));
ASSERT_EQ(std::vector<int>({ 1, 0, 1, 0, 3, 1 }), output);
@@ -163,12 +161,11 @@
const std::vector<ValueHolder>& cinput = input;
auto ctaref = MakeTransformArrayRef(cinput, ref);
- static_assert(std::is_same<int, decltype(ctaref)::value_type>::value, "value_type");
- static_assert(std::is_same<const int*, decltype(ctaref)::pointer>::value, "pointer");
- static_assert(std::is_same<const int&, decltype(ctaref)::reference>::value, "reference");
- static_assert(std::is_same<const int*, decltype(ctaref)::const_pointer>::value, "const_pointer");
- static_assert(std::is_same<const int&, decltype(ctaref)::const_reference>::value,
- "const_reference");
+ static_assert(std::is_same_v<int, decltype(ctaref)::value_type>);
+ static_assert(std::is_same_v<const int*, decltype(ctaref)::pointer>);
+ static_assert(std::is_same_v<const int&, decltype(ctaref)::reference>);
+ static_assert(std::is_same_v<const int*, decltype(ctaref)::const_pointer>);
+ static_assert(std::is_same_v<const int&, decltype(ctaref)::const_reference>);
std::copy(ctaref.begin(), ctaref.end(), std::back_inserter(output));
ASSERT_EQ(std::vector<int>({ 1, 0, 1, 0, 3, 1 }), output);
diff --git a/libartbase/base/transform_iterator.h b/libartbase/base/transform_iterator.h
index 5b0574d..062c88b 100644
--- a/libartbase/base/transform_iterator.h
+++ b/libartbase/base/transform_iterator.h
@@ -39,23 +39,20 @@
template <typename BaseIterator, typename Function>
class TransformIterator {
private:
- static_assert(std::is_base_of<
- std::input_iterator_tag,
- typename std::iterator_traits<BaseIterator>::iterator_category>::value,
+ static_assert(std::is_base_of_v<std::input_iterator_tag,
+ typename std::iterator_traits<BaseIterator>::iterator_category>,
"Transform iterator base must be an input iterator.");
using InputType = typename std::iterator_traits<BaseIterator>::reference;
- using ResultType = typename std::result_of<Function(InputType)>::type;
+ using ResultType = std::result_of_t<Function(InputType)>;
public:
using iterator_category = typename std::iterator_traits<BaseIterator>::iterator_category;
- using value_type =
- typename std::remove_const<typename std::remove_reference<ResultType>::type>::type;
+ using value_type = std::remove_const_t<std::remove_reference_t<ResultType>>;
using difference_type = typename std::iterator_traits<BaseIterator>::difference_type;
- using pointer = typename std::conditional<
- std::is_reference<ResultType>::value,
- typename std::add_pointer<typename std::remove_reference<ResultType>::type>::type,
- TransformIterator>::type;
+ using pointer = std::conditional_t<std::is_reference_v<ResultType>,
+ std::add_pointer_t<std::remove_reference_t<ResultType>>,
+ TransformIterator>;
using reference = ResultType;
TransformIterator(BaseIterator base, Function fn)
@@ -78,10 +75,9 @@
}
TransformIterator& operator--() {
- static_assert(
- std::is_base_of<std::bidirectional_iterator_tag,
- typename std::iterator_traits<BaseIterator>::iterator_category>::value,
- "BaseIterator must be bidirectional iterator to use operator--()");
+ static_assert(std::is_base_of_v<std::bidirectional_iterator_tag,
+ typename std::iterator_traits<BaseIterator>::iterator_category>,
+ "BaseIterator must be bidirectional iterator to use operator--()");
--data_.base_;
return *this;
}
@@ -97,34 +93,30 @@
}
reference operator[](difference_type n) const {
- static_assert(
- std::is_base_of<std::random_access_iterator_tag,
- typename std::iterator_traits<BaseIterator>::iterator_category>::value,
- "BaseIterator must be random access iterator to use operator[]");
+ static_assert(std::is_base_of_v<std::random_access_iterator_tag,
+ typename std::iterator_traits<BaseIterator>::iterator_category>,
+ "BaseIterator must be random access iterator to use operator[]");
return GetFunction()(base()[n]);
}
TransformIterator operator+(difference_type n) const {
- static_assert(
- std::is_base_of<std::random_access_iterator_tag,
- typename std::iterator_traits<BaseIterator>::iterator_category>::value,
- "BaseIterator must be random access iterator to use operator+");
+ static_assert(std::is_base_of_v<std::random_access_iterator_tag,
+ typename std::iterator_traits<BaseIterator>::iterator_category>,
+ "BaseIterator must be random access iterator to use operator+");
return TransformIterator(base() + n, GetFunction());
}
TransformIterator operator-(difference_type n) const {
- static_assert(
- std::is_base_of<std::random_access_iterator_tag,
- typename std::iterator_traits<BaseIterator>::iterator_category>::value,
- "BaseIterator must be random access iterator to use operator-");
+ static_assert(std::is_base_of_v<std::random_access_iterator_tag,
+ typename std::iterator_traits<BaseIterator>::iterator_category>,
+ "BaseIterator must be random access iterator to use operator-");
return TransformIterator(base() - n, GetFunction());
}
difference_type operator-(const TransformIterator& other) const {
- static_assert(
- std::is_base_of<std::random_access_iterator_tag,
- typename std::iterator_traits<BaseIterator>::iterator_category>::value,
- "BaseIterator must be random access iterator to use operator-");
+ static_assert(std::is_base_of_v<std::random_access_iterator_tag,
+ typename std::iterator_traits<BaseIterator>::iterator_category>,
+ "BaseIterator must be random access iterator to use operator-");
return base() - other.base();
}
diff --git a/libartbase/base/transform_iterator_test.cc b/libartbase/base/transform_iterator_test.cc
index 5a5c37d..3d16465 100644
--- a/libartbase/base/transform_iterator_test.cc
+++ b/libartbase/base/transform_iterator_test.cc
@@ -45,32 +45,28 @@
std::vector<int> output;
using vector_titer = decltype(MakeTransformIterator(input.begin(), add1));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_titer::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_titer::value_type>::value, "value_type");
- static_assert(std::is_same<vector_titer, vector_titer::pointer>::value, "pointer");
- static_assert(std::is_same<int, vector_titer::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_titer::iterator_category>);
+ static_assert(std::is_same_v<int, vector_titer::value_type>);
+ static_assert(std::is_same_v<vector_titer, vector_titer::pointer>);
+ static_assert(std::is_same_v<int, vector_titer::reference>);
using vector_ctiter = decltype(MakeTransformIterator(input.cbegin(), add1));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_ctiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_ctiter::value_type>::value, "value_type");
- static_assert(std::is_same<vector_ctiter, vector_ctiter::pointer>::value, "pointer");
- static_assert(std::is_same<int, vector_ctiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_ctiter::iterator_category>);
+ static_assert(std::is_same_v<int, vector_ctiter::value_type>);
+ static_assert(std::is_same_v<vector_ctiter, vector_ctiter::pointer>);
+ static_assert(std::is_same_v<int, vector_ctiter::reference>);
using vector_rtiter = decltype(MakeTransformIterator(input.rbegin(), add1));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_rtiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_rtiter::value_type>::value, "value_type");
- static_assert(std::is_same<vector_rtiter, vector_rtiter::pointer>::value, "pointer");
- static_assert(std::is_same<int, vector_rtiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_rtiter::iterator_category>);
+ static_assert(std::is_same_v<int, vector_rtiter::value_type>);
+ static_assert(std::is_same_v<vector_rtiter, vector_rtiter::pointer>);
+ static_assert(std::is_same_v<int, vector_rtiter::reference>);
using vector_crtiter = decltype(MakeTransformIterator(input.crbegin(), add1));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_crtiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_crtiter::value_type>::value, "value_type");
- static_assert(std::is_same<vector_crtiter, vector_crtiter::pointer>::value, "pointer");
- static_assert(std::is_same<int, vector_crtiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_crtiter::iterator_category>);
+ static_assert(std::is_same_v<int, vector_crtiter::value_type>);
+ static_assert(std::is_same_v<vector_crtiter, vector_crtiter::pointer>);
+ static_assert(std::is_same_v<int, vector_crtiter::reference>);
std::copy(MakeTransformIterator(input.begin(), add1),
MakeTransformIterator(input.end(), add1),
@@ -134,11 +130,11 @@
// Test iterator->const_iterator conversion and comparison.
auto it = MakeTransformIterator(input.begin(), add1);
decltype(MakeTransformIterator(input.cbegin(), add1)) cit = it;
- static_assert(!std::is_same<decltype(it), decltype(cit)>::value, "Types must be different");
+ static_assert(!std::is_same_v<decltype(it), decltype(cit)>, "Types must be different");
ASSERT_EQ(it, cit);
auto rit = MakeTransformIterator(input.rbegin(), add1);
decltype(MakeTransformIterator(input.crbegin(), add1)) crit(rit);
- static_assert(!std::is_same<decltype(rit), decltype(crit)>::value, "Types must be different");
+ static_assert(!std::is_same_v<decltype(rit), decltype(crit)>, "Types must be different");
ASSERT_EQ(rit, crit);
}
@@ -148,32 +144,28 @@
std::vector<int> output;
using list_titer = decltype(MakeTransformIterator(input.begin(), sub1));
- static_assert(std::is_same<std::bidirectional_iterator_tag,
- list_titer::iterator_category>::value, "category");
- static_assert(std::is_same<int, list_titer::value_type>::value, "value_type");
- static_assert(std::is_same<list_titer, list_titer::pointer>::value, "pointer");
- static_assert(std::is_same<int, list_titer::reference>::value, "reference");
+ static_assert(std::is_same_v<std::bidirectional_iterator_tag, list_titer::iterator_category>);
+ static_assert(std::is_same_v<int, list_titer::value_type>);
+ static_assert(std::is_same_v<list_titer, list_titer::pointer>);
+ static_assert(std::is_same_v<int, list_titer::reference>);
using list_ctiter = decltype(MakeTransformIterator(input.cbegin(), sub1));
- static_assert(std::is_same<std::bidirectional_iterator_tag,
- list_ctiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, list_ctiter::value_type>::value, "value_type");
- static_assert(std::is_same<list_ctiter, list_ctiter::pointer>::value, "pointer");
- static_assert(std::is_same<int, list_ctiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::bidirectional_iterator_tag, list_ctiter::iterator_category>);
+ static_assert(std::is_same_v<int, list_ctiter::value_type>);
+ static_assert(std::is_same_v<list_ctiter, list_ctiter::pointer>);
+ static_assert(std::is_same_v<int, list_ctiter::reference>);
using list_rtiter = decltype(MakeTransformIterator(input.rbegin(), sub1));
- static_assert(std::is_same<std::bidirectional_iterator_tag,
- list_rtiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, list_rtiter::value_type>::value, "value_type");
- static_assert(std::is_same<list_rtiter, list_rtiter::pointer>::value, "pointer");
- static_assert(std::is_same<int, list_rtiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::bidirectional_iterator_tag, list_rtiter::iterator_category>);
+ static_assert(std::is_same_v<int, list_rtiter::value_type>);
+ static_assert(std::is_same_v<list_rtiter, list_rtiter::pointer>);
+ static_assert(std::is_same_v<int, list_rtiter::reference>);
using list_crtiter = decltype(MakeTransformIterator(input.crbegin(), sub1));
- static_assert(std::is_same<std::bidirectional_iterator_tag,
- list_crtiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, list_crtiter::value_type>::value, "value_type");
- static_assert(std::is_same<list_crtiter, list_crtiter::pointer>::value, "pointer");
- static_assert(std::is_same<int, list_crtiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::bidirectional_iterator_tag, list_crtiter::iterator_category>);
+ static_assert(std::is_same_v<int, list_crtiter::value_type>);
+ static_assert(std::is_same_v<list_crtiter, list_crtiter::pointer>);
+ static_assert(std::is_same_v<int, list_crtiter::reference>);
std::copy(MakeTransformIterator(input.begin(), sub1),
MakeTransformIterator(input.end(), sub1),
@@ -202,7 +194,7 @@
// Test iterator->const_iterator conversion and comparison.
auto it = MakeTransformIterator(input.begin(), sub1);
decltype(MakeTransformIterator(input.cbegin(), sub1)) cit = it;
- static_assert(!std::is_same<decltype(it), decltype(cit)>::value, "Types must be different");
+ static_assert(!std::is_same_v<decltype(it), decltype(cit)>, "Types must be different");
ASSERT_EQ(it, cit);
}
@@ -212,18 +204,16 @@
std::vector<int> output;
using flist_titer = decltype(MakeTransformIterator(input.begin(), mul3));
- static_assert(std::is_same<std::forward_iterator_tag,
- flist_titer::iterator_category>::value, "category");
- static_assert(std::is_same<int, flist_titer::value_type>::value, "value_type");
- static_assert(std::is_same<flist_titer, flist_titer::pointer>::value, "pointer");
- static_assert(std::is_same<int, flist_titer::reference>::value, "reference");
+ static_assert(std::is_same_v<std::forward_iterator_tag, flist_titer::iterator_category>);
+ static_assert(std::is_same_v<int, flist_titer::value_type>);
+ static_assert(std::is_same_v<flist_titer, flist_titer::pointer>);
+ static_assert(std::is_same_v<int, flist_titer::reference>);
using flist_ctiter = decltype(MakeTransformIterator(input.cbegin(), mul3));
- static_assert(std::is_same<std::forward_iterator_tag,
- flist_ctiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, flist_ctiter::value_type>::value, "value_type");
- static_assert(std::is_same<flist_ctiter, flist_ctiter::pointer>::value, "pointer");
- static_assert(std::is_same<int, flist_ctiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::forward_iterator_tag, flist_ctiter::iterator_category>);
+ static_assert(std::is_same_v<int, flist_ctiter::value_type>);
+ static_assert(std::is_same_v<flist_ctiter, flist_ctiter::pointer>);
+ static_assert(std::is_same_v<int, flist_ctiter::reference>);
std::copy(MakeTransformIterator(input.begin(), mul3),
MakeTransformIterator(input.end(), mul3),
@@ -240,7 +230,7 @@
// Test iterator->const_iterator conversion and comparison.
auto it = MakeTransformIterator(input.begin(), mul3);
decltype(MakeTransformIterator(input.cbegin(), mul3)) cit = it;
- static_assert(!std::is_same<decltype(it), decltype(cit)>::value, "Types must be different");
+ static_assert(!std::is_same_v<decltype(it), decltype(cit)>, "Types must be different");
ASSERT_EQ(it, cit);
}
@@ -250,32 +240,28 @@
std::vector<int> output;
using vector_titer = decltype(MakeTransformIterator(input.begin(), ref));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_titer::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_titer::value_type>::value, "value_type");
- static_assert(std::is_same<const int*, vector_titer::pointer>::value, "pointer");
- static_assert(std::is_same<const int&, vector_titer::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_titer::iterator_category>);
+ static_assert(std::is_same_v<int, vector_titer::value_type>);
+ static_assert(std::is_same_v<const int*, vector_titer::pointer>);
+ static_assert(std::is_same_v<const int&, vector_titer::reference>);
using vector_ctiter = decltype(MakeTransformIterator(input.cbegin(), ref));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_ctiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_ctiter::value_type>::value, "value_type");
- static_assert(std::is_same<const int*, vector_ctiter::pointer>::value, "pointer");
- static_assert(std::is_same<const int&, vector_ctiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_ctiter::iterator_category>);
+ static_assert(std::is_same_v<int, vector_ctiter::value_type>);
+ static_assert(std::is_same_v<const int*, vector_ctiter::pointer>);
+ static_assert(std::is_same_v<const int&, vector_ctiter::reference>);
using vector_rtiter = decltype(MakeTransformIterator(input.rbegin(), ref));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_rtiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_rtiter::value_type>::value, "value_type");
- static_assert(std::is_same<const int*, vector_rtiter::pointer>::value, "pointer");
- static_assert(std::is_same<const int&, vector_rtiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_rtiter::iterator_category>);
+ static_assert(std::is_same_v<int, vector_rtiter::value_type>);
+ static_assert(std::is_same_v<const int*, vector_rtiter::pointer>);
+ static_assert(std::is_same_v<const int&, vector_rtiter::reference>);
using vector_crtiter = decltype(MakeTransformIterator(input.crbegin(), ref));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_crtiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_crtiter::value_type>::value, "value_type");
- static_assert(std::is_same<const int*, vector_crtiter::pointer>::value, "pointer");
- static_assert(std::is_same<const int&, vector_crtiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_crtiter::iterator_category>);
+ static_assert(std::is_same_v<int, vector_crtiter::value_type>);
+ static_assert(std::is_same_v<const int*, vector_crtiter::pointer>);
+ static_assert(std::is_same_v<const int&, vector_crtiter::reference>);
std::copy(MakeTransformIterator(input.begin(), ref),
MakeTransformIterator(input.end(), ref),
@@ -343,18 +329,16 @@
std::vector<int> output;
using vector_titer = decltype(MakeTransformIterator(input.begin(), ref));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_titer::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_titer::value_type>::value, "value_type");
- static_assert(std::is_same<int*, vector_titer::pointer>::value, "pointer");
- static_assert(std::is_same<int&, vector_titer::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_titer::iterator_category>);
+ static_assert(std::is_same_v<int, vector_titer::value_type>);
+ static_assert(std::is_same_v<int*, vector_titer::pointer>);
+ static_assert(std::is_same_v<int&, vector_titer::reference>);
using vector_rtiter = decltype(MakeTransformIterator(input.rbegin(), ref));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_rtiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_rtiter::value_type>::value, "value_type");
- static_assert(std::is_same<int*, vector_rtiter::pointer>::value, "pointer");
- static_assert(std::is_same<int&, vector_rtiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_rtiter::iterator_category>);
+ static_assert(std::is_same_v<int, vector_rtiter::value_type>);
+ static_assert(std::is_same_v<int*, vector_rtiter::pointer>);
+ static_assert(std::is_same_v<int&, vector_rtiter::reference>);
std::copy(MakeTransformIterator(input.begin(), ref),
MakeTransformIterator(input.end(), ref),
@@ -411,32 +395,28 @@
std::vector<int> output;
using vector_titer = decltype(MakeTransformIterator(input.begin(), ref));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_titer::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_titer::value_type>::value, "value_type");
- static_assert(std::is_same<int*, vector_titer::pointer>::value, "pointer");
- static_assert(std::is_same<int&, vector_titer::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_titer::iterator_category>);
+ static_assert(std::is_same_v<int, vector_titer::value_type>);
+ static_assert(std::is_same_v<int*, vector_titer::pointer>);
+ static_assert(std::is_same_v<int&, vector_titer::reference>);
using vector_ctiter = decltype(MakeTransformIterator(input.cbegin(), ref));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_ctiter::iterator_category>::value, "category");
- // static_assert(std::is_same<int, vector_ctiter::value_type>::value, "value_type");
- static_assert(std::is_same<const int*, vector_ctiter::pointer>::value, "pointer");
- static_assert(std::is_same<const int&, vector_ctiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_ctiter::iterator_category>);
+ static_assert(std::is_same_v<int, vector_ctiter::value_type>);
+ static_assert(std::is_same_v<const int*, vector_ctiter::pointer>);
+ static_assert(std::is_same_v<const int&, vector_ctiter::reference>);
using vector_rtiter = decltype(MakeTransformIterator(input.rbegin(), ref));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_rtiter::iterator_category>::value, "category");
- static_assert(std::is_same<int, vector_rtiter::value_type>::value, "value_type");
- static_assert(std::is_same<int*, vector_rtiter::pointer>::value, "pointer");
- static_assert(std::is_same<int&, vector_rtiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_rtiter::iterator_category>);
+ static_assert(std::is_same_v<int, vector_rtiter::value_type>);
+ static_assert(std::is_same_v<int*, vector_rtiter::pointer>);
+ static_assert(std::is_same_v<int&, vector_rtiter::reference>);
using vector_crtiter = decltype(MakeTransformIterator(input.crbegin(), ref));
- static_assert(std::is_same<std::random_access_iterator_tag,
- vector_crtiter::iterator_category>::value, "category");
- // static_assert(std::is_same<int, vector_crtiter::value_type>::value, "value_type");
- static_assert(std::is_same<const int*, vector_crtiter::pointer>::value, "pointer");
- static_assert(std::is_same<const int&, vector_crtiter::reference>::value, "reference");
+ static_assert(std::is_same_v<std::random_access_iterator_tag, vector_crtiter::iterator_category>);
+ static_assert(std::is_same_v<int, vector_crtiter::value_type>);
+ static_assert(std::is_same_v<const int*, vector_crtiter::pointer>);
+ static_assert(std::is_same_v<const int&, vector_crtiter::reference>);
std::copy(MakeTransformIterator(input.begin(), ref),
MakeTransformIterator(input.end(), ref),
@@ -500,11 +480,11 @@
// Test iterator->const_iterator conversion and comparison.
auto it = MakeTransformIterator(input.begin(), ref);
decltype(MakeTransformIterator(input.cbegin(), ref)) cit = it;
- static_assert(!std::is_same<decltype(it), decltype(cit)>::value, "Types must be different");
+ static_assert(!std::is_same_v<decltype(it), decltype(cit)>, "Types must be different");
ASSERT_EQ(it, cit);
auto rit = MakeTransformIterator(input.rbegin(), ref);
decltype(MakeTransformIterator(input.crbegin(), ref)) crit(rit);
- static_assert(!std::is_same<decltype(rit), decltype(crit)>::value, "Types must be different");
+ static_assert(!std::is_same_v<decltype(rit), decltype(crit)>, "Types must be different");
ASSERT_EQ(rit, crit);
// Test writing through the transform iterator.
diff --git a/libartbase/base/variant_map.h b/libartbase/base/variant_map.h
index 4244c9f..8d416e4 100644
--- a/libartbase/base/variant_map.h
+++ b/libartbase/base/variant_map.h
@@ -395,8 +395,7 @@
template <typename TK, typename TValue, typename ... Rest>
void InitializeParameters(const TK& key, const TValue& value, const Rest& ... rest) {
- static_assert(
- std::is_same<TK, TKey<TValue>>::value, "The 0th/2nd/4th/etc parameters must be a key");
+ static_assert(std::is_same_v<TK, TKey<TValue>>, "The 0th/2nd/4th/etc parameters must be a key");
const TKey<TValue>& key_refined = key;
@@ -459,7 +458,7 @@
template <typename TValue>
static void StaticAssertKeyType() {
- static_assert(std::is_base_of<VariantMapKey<TValue>, TKey<TValue>>::value,
+ static_assert(std::is_base_of_v<VariantMapKey<TValue>, TKey<TValue>>,
"The provided key type (TKey) must be a subclass of VariantMapKey");
}
diff --git a/libprofile/profile/profile_compilation_info.cc b/libprofile/profile/profile_compilation_info.cc
index b5cc6b7..f135805 100644
--- a/libprofile/profile/profile_compilation_info.cc
+++ b/libprofile/profile/profile_compilation_info.cc
@@ -2020,9 +2020,11 @@
os << " [num_method_ids=" << dex_data->num_method_ids << "]";
const DexFile* dex_file = nullptr;
for (const DexFile* current : dex_files) {
- if (GetBaseKeyViewFromAugmentedKey(dex_data->profile_key) == current->GetLocation() &&
- dex_data->checksum == current->GetLocationChecksum()) {
+ if (GetBaseKeyViewFromAugmentedKey(dex_data->profile_key) ==
+ GetProfileDexFileBaseKeyView(current->GetLocation()) &&
+ ChecksumMatch(dex_data->checksum, current->GetLocationChecksum())) {
dex_file = current;
+ break;
}
}
os << "\n\thot methods: ";
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index acfbcb0..a4bc1fb 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -135,7 +135,7 @@
ObjPtr<mirror::Class> ClassTable::Lookup(const char* descriptor, size_t hash) {
DescriptorHashPair pair(descriptor, hash);
ReaderMutexLock mu(Thread::Current(), lock_);
- for (ClassSet& class_set : classes_) {
+ for (ClassSet& class_set : ReverseRange(classes_)) {
auto it = class_set.FindWithHash(pair, hash);
if (it != class_set.end()) {
return it->Read();
@@ -153,19 +153,6 @@
classes_.back().InsertWithHash(TableSlot(klass, hash), hash);
}
-bool ClassTable::Remove(const char* descriptor) {
- DescriptorHashPair pair(descriptor, ComputeModifiedUtf8Hash(descriptor));
- WriterMutexLock mu(Thread::Current(), lock_);
- for (ClassSet& class_set : classes_) {
- auto it = class_set.find(pair);
- if (it != class_set.end()) {
- class_set.erase(it);
- return true;
- }
- }
- return false;
-}
-
bool ClassTable::InsertStrongRoot(ObjPtr<mirror::Object> obj) {
WriterMutexLock mu(Thread::Current(), lock_);
DCHECK(obj != nullptr);
@@ -209,7 +196,12 @@
void ClassTable::AddClassSet(ClassSet&& set) {
WriterMutexLock mu(Thread::Current(), lock_);
- classes_.insert(classes_.begin(), std::move(set));
+ // Insert before the last (unfrozen) table since we add new classes into the back.
+ // Keep the order of previous frozen tables unchanged, so that we can can remember
+ // the number of searched frozen tables and not search them again.
+ // TODO: Make use of this in `ClassLinker::FindClass()`.
+ DCHECK(!classes_.empty());
+ classes_.insert(classes_.end() - 1, std::move(set));
}
void ClassTable::ClearStrongRoots() {
diff --git a/runtime/class_table.h b/runtime/class_table.h
index 4c5fc62..3377f14 100644
--- a/runtime/class_table.h
+++ b/runtime/class_table.h
@@ -220,11 +220,6 @@
REQUIRES(!lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Returns true if the class was found and removed, false otherwise.
- bool Remove(const char* descriptor)
- REQUIRES(!lock_)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
// Return true if we inserted the strong root, false if it already exists.
bool InsertStrongRoot(ObjPtr<mirror::Object> obj)
REQUIRES(!lock_)
diff --git a/runtime/class_table_test.cc b/runtime/class_table_test.cc
index d9f53ed..7dbeba5 100644
--- a/runtime/class_table_test.cc
+++ b/runtime/class_table_test.cc
@@ -137,12 +137,7 @@
});
EXPECT_EQ(classes.size(), 1u);
- // Test remove.
- table.Remove(descriptor_x);
- EXPECT_TRUE(table.LookupByDescriptor(h_X.Get()) == nullptr);
-
// Test that reading a class set from memory works.
- table.Insert(h_X.Get());
ClassTable::ClassSet temp_set;
table.Visit([&temp_set](ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
temp_set.insert(ClassTable::TableSlot(klass));
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 14b8315..7f29655 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -337,13 +337,13 @@
size_t num_searched_frozen_tables) {
Locks::intern_table_lock_->AssertHeld(Thread::Current());
auto mid = tables_.begin() + num_searched_frozen_tables;
- for (auto it = tables_.begin(); it != mid; ++it) {
- DCHECK(it->set_.FindWithHash(GcRoot<mirror::String>(s), hash) == it->set_.end());
+ for (Table::InternalTable& table : MakeIterationRange(tables_.begin(), mid)) {
+ DCHECK(table.set_.FindWithHash(GcRoot<mirror::String>(s), hash) == table.set_.end());
}
- for (auto it = mid, end = tables_.end(); it != end; ++it) {
- auto set_it = it->set_.FindWithHash(GcRoot<mirror::String>(s), hash);
- if (set_it != it->set_.end()) {
- return set_it->Read();
+ for (Table::InternalTable& table : ReverseRange(MakeIterationRange(mid, tables_.end()))) {
+ auto it = table.set_.FindWithHash(GcRoot<mirror::String>(s), hash);
+ if (it != table.set_.end()) {
+ return it->Read();
}
}
return nullptr;
@@ -352,7 +352,7 @@
FLATTEN
ObjPtr<mirror::String> InternTable::Table::Find(const Utf8String& string, uint32_t hash) {
Locks::intern_table_lock_->AssertHeld(Thread::Current());
- for (InternalTable& table : tables_) {
+ for (InternalTable& table : ReverseRange(tables_)) {
auto it = table.set_.FindWithHash(string, hash);
if (it != table.set_.end()) {
return it->Read();
diff --git a/runtime/jni/jni_internal.cc b/runtime/jni/jni_internal.cc
index 8463bc2..7a25b4b 100644
--- a/runtime/jni/jni_internal.cc
+++ b/runtime/jni/jni_internal.cc
@@ -899,6 +899,8 @@
// going quite the way they expect.
LOG(WARNING) << "JNI WARNING: DeleteLocalRef(" << obj << ") "
<< "failed to find entry";
+ // Investigating b/228295454: Scudo ERROR: internal map failure (NO MEMORY).
+ soa.Self()->DumpJavaStack(LOG_STREAM(WARNING));
}
}
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 74c286f..ec0ac73 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3636,8 +3636,14 @@
const RegType& referrer = GetDeclaringClass();
if ((IsSdkVersionSetAndAtLeast(api_level_, SdkVersion::kP) || !referrer.IsUnresolvedTypes()) &&
!referrer.CanAccess(*result)) {
- Fail(VERIFY_ERROR_ACCESS_CLASS) << "(possibly) illegal class access: '"
- << referrer << "' -> '" << *result << "'";
+ if (IsAotMode()) {
+ Fail(VERIFY_ERROR_ACCESS_CLASS);
+ VLOG(verifier)
+ << "(possibly) illegal class access: '" << referrer << "' -> '" << *result << "'";
+ } else {
+ Fail(VERIFY_ERROR_ACCESS_CLASS)
+ << "(possibly) illegal class access: '" << referrer << "' -> '" << *result << "'";
+ }
}
}
return *result;
diff --git a/test/530-checker-loops-try-catch/expected-stderr.txt b/test/530-checker-loops-try-catch/expected-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/530-checker-loops-try-catch/expected-stderr.txt
diff --git a/test/530-checker-loops-try-catch/expected-stdout.txt b/test/530-checker-loops-try-catch/expected-stdout.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/530-checker-loops-try-catch/expected-stdout.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/530-checker-loops-try-catch/info.txt b/test/530-checker-loops-try-catch/info.txt
new file mode 100644
index 0000000..5ff3c22
--- /dev/null
+++ b/test/530-checker-loops-try-catch/info.txt
@@ -0,0 +1 @@
+Test on loop optimizations, in particular with try catches.
diff --git a/test/530-checker-loops-try-catch/src/Main.java b/test/530-checker-loops-try-catch/src/Main.java
new file mode 100644
index 0000000..8d44b65
--- /dev/null
+++ b/test/530-checker-loops-try-catch/src/Main.java
@@ -0,0 +1,1558 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Test on loop optimizations, in particular with try catches.
+//
+public class Main {
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$geo1(int) loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$geo1(int) loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Mul loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$geo1(int) loop_optimization (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 1410065408 loop:none
+ /// CHECK-DAG: <<Mul:i\d+>> Mul [<<Par>>,<<Int>>] loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Mul>>,<<Zer>>] loop:none
+ /// CHECK-DAG: Return [<<Add>>] loop:none
+
+ /// CHECK-START: int Main.$noinline$geo1(int) loop_optimization (after)
+ /// CHECK-NOT: Phi
+ private static int $noinline$geo1(int a) {
+ for (int i = 0; i < 10; i++) {
+ a *= 10;
+ }
+
+ // Outer try catch does not block loop optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$geo1_Blocking(int) loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$geo1_Blocking(int) loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Mul loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$geo1_Blocking(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Mul loop:<<Loop>>
+ private static int $noinline$geo1_Blocking(int a) {
+ for (int i = 0; i < 10; i++) {
+ a *= 10;
+
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$geo2(int) loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$geo2(int) loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Shl loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$geo2(int) loop_optimization (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 1024 loop:none
+ /// CHECK-DAG: <<Mul:i\d+>> Mul [<<Par>>,<<Int>>] loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Mul>>,<<Zer>>] loop:none
+ /// CHECK-DAG: Return [<<Add>>] loop:none
+
+ /// CHECK-START: int Main.$noinline$geo2(int) loop_optimization (after)
+ /// CHECK-NOT: Phi
+ private static int $noinline$geo2(int a) {
+ for (int i = 0; i < 10; i++) {
+ a <<= 1;
+ }
+
+ // Outer try catch does not block loop optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$geo2_Blocking(int) loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$geo2_Blocking(int) loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Shl loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$geo2_Blocking(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Shl loop:<<Loop>>
+ private static int $noinline$geo2_Blocking(int a) {
+ for (int i = 0; i < 10; i++) {
+ a <<= 1;
+
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$geo3(int) loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$geo3(int) loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Div loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$geo3(int) loop_optimization (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 59049 loop:none
+ /// CHECK-DAG: <<Div:i\d+>> Div [<<Par>>,<<Int>>] loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Div>>,<<Zer>>] loop:none
+ /// CHECK-DAG: Return [<<Add>>] loop:none
+
+ /// CHECK-START: int Main.$noinline$geo3(int) loop_optimization (after)
+ /// CHECK-NOT: Phi
+ private static int $noinline$geo3(int a) {
+ for (int i = 0; i < 10; i++) {
+ a /= 3;
+ }
+
+ // Outer try catch does not block loop optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$geo3_Blocking(int) loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$geo3_Blocking(int) loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Div loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$geo3_Blocking(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Div loop:<<Loop>>
+ private static int $noinline$geo3_Blocking(int a) {
+ for (int i = 0; i < 10; i++) {
+ a /= 3;
+
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ return a;
+ }
+
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$geo4(int) loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$geo4(int) loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Rem loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$geo4(int) loop_optimization (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 7 loop:none
+ /// CHECK-DAG: <<Rem:i\d+>> Rem [<<Par>>,<<Int>>] loop:none
+ /// CHECK-DAG: Return [<<Rem>>] loop:none
+
+ /// CHECK-START: int Main.$noinline$geo4(int) loop_optimization (after)
+ /// CHECK-NOT: Phi
+ private static int $noinline$geo4(int a) {
+ for (int i = 0; i < 10; i++) {
+ a %= 7; // a wrap-around induction
+ }
+
+ // Outer try catch does not block loop optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$geo4_Blocking(int) loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$geo4_Blocking(int) loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Rem loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$geo4_Blocking(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Rem loop:<<Loop>>
+ private static int $noinline$geo4_Blocking(int a) {
+ for (int i = 0; i < 10; i++) {
+ a %= 7; // a wrap-around induction
+
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$geo5() loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$geo5() loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Shr loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$geo5() loop_optimization (after)
+ /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Int1:i\d+>> IntConstant 2147483647 loop:none
+ /// CHECK-DAG: <<Int2:i\d+>> IntConstant 1024 loop:none
+ /// CHECK-DAG: <<Div:i\d+>> Div [<<Int1>>,<<Int2>>] loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Div>>,<<Zero>>] loop:none
+ /// CHECK-DAG: Return [<<Add>>] loop:none
+
+ /// CHECK-START: int Main.$noinline$geo5() loop_optimization (after)
+ /// CHECK-NOT: Phi
+ private static int $noinline$geo5() {
+ int a = 0x7fffffff;
+ for (int i = 0; i < 10; i++) {
+ a >>= 1;
+ }
+
+ // Outer try catch does not block loop optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$geo5_Blocking() loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$geo5_Blocking() loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Shr loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$geo5_Blocking() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Shr loop:<<Loop>>
+ private static int $noinline$geo5_Blocking() {
+ int a = 0x7fffffff;
+ for (int i = 0; i < 10; i++) {
+ a >>= 1;
+
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ return a;
+ }
+
+ // Tests taken from 530-checker-loops4
+ private static void $noinline$loops4Tests() {
+ int m = 1410065408;
+ for (int i = -100; i <= 100; i++) {
+ expectEquals(m * i, $noinline$geo1(i));
+ expectEquals(m * i, $noinline$geo1_Blocking(i));
+ }
+ for (int i = 1; i <= 1000000000; i *= 10) {
+ expectEquals(m * i, $noinline$geo1(i));
+ expectEquals(m * i, $noinline$geo1_Blocking(i));
+ expectEquals(-m * i, $noinline$geo1(-i));
+ expectEquals(-m * i, $noinline$geo1_Blocking(-i));
+ }
+
+ for (int i = -100; i <= 100; i++) {
+ expectEquals(i << 10, $noinline$geo2(i));
+ expectEquals(i << 10, $noinline$geo2_Blocking(i));
+ }
+ for (int i = 0; i < 22; i++) {
+ expectEquals(1 << (i + 10), $noinline$geo2(1 << i));
+ expectEquals(1 << (i + 10), $noinline$geo2_Blocking(1 << i));
+ }
+ expectEquals(0x80000400, $noinline$geo2(0x00200001));
+ expectEquals(0x80000400, $noinline$geo2_Blocking(0x00200001));
+ expectEquals(0x00000000, $noinline$geo2(0x00400000));
+ expectEquals(0x00000000, $noinline$geo2_Blocking(0x00400000));
+ expectEquals(0x00000400, $noinline$geo2(0x00400001));
+ expectEquals(0x00000400, $noinline$geo2_Blocking(0x00400001));
+
+ int d = 59049;
+ for (int i = -100; i <= 100; i++) {
+ expectEquals(0, $noinline$geo3(i));
+ expectEquals(0, $noinline$geo3_Blocking(i));
+ }
+ for (int i = 1; i <= 100; i++) {
+ expectEquals(i, $noinline$geo3(i * d));
+ expectEquals(i, $noinline$geo3_Blocking(i * d));
+ expectEquals(i, $noinline$geo3(i * d + 1));
+ expectEquals(i, $noinline$geo3_Blocking(i * d + 1));
+ expectEquals(-i, $noinline$geo3(-i * d));
+ expectEquals(-i, $noinline$geo3_Blocking(-i * d));
+ expectEquals(-i, $noinline$geo3(-i * d - 1));
+ expectEquals(-i, $noinline$geo3_Blocking(-i * d - 1));
+ }
+
+ for (int i = -100; i <= 100; i++) {
+ expectEquals(i % 7, $noinline$geo4(i));
+ expectEquals(i % 7, $noinline$geo4_Blocking(i));
+ }
+
+ expectEquals(0x1fffff, $noinline$geo5());
+ expectEquals(0x1fffff, $noinline$geo5_Blocking());
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$poly1() loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$poly1() loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$poly1() loop_optimization (after)
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 55 loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Int>>,<<Zer>>] loop:none
+ /// CHECK-DAG: Return [<<Add>>] loop:none
+
+ /// CHECK-START: int Main.$noinline$poly1() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 55 loop:none
+ /// CHECK-DAG: Return [<<Int>>] loop:none
+
+ /// CHECK-START: int Main.$noinline$poly1() loop_optimization (after)
+ /// CHECK-NOT: Phi
+ private static int $noinline$poly1() {
+ int a = 0;
+ for (int i = 0; i <= 10; i++) {
+ a += i;
+ }
+
+ // Outer try catch does not block loop optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$poly1_Blocking() loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$poly1_Blocking() loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$poly1_Blocking() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ private static int $noinline$poly1_Blocking() {
+ int a = 0;
+ for (int i = 0; i <= 10; i++) {
+ a += i;
+
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+
+ return a;
+ }
+
+ // Multiplication in linear induction has been optimized earlier,
+ // but that does not stop the induction variable recognition
+ // and loop optimizer.
+ //
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$poly2(int) loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$poly2(int) loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Shl loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$poly2(int) loop_optimization (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 185 loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Int>>,<<Par>>] loop:none
+ /// CHECK-DAG: Return [<<Add>>] loop:none
+
+ /// CHECK-START: int Main.$noinline$poly2(int) loop_optimization (after)
+ /// CHECK-NOT: Phi
+ private static int $noinline$poly2(int a) {
+ for (int i = 0; i < 10; i++) {
+ int k = 3 * i + 5;
+ a += k;
+ }
+
+ // Outer try catch does not block loop optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$poly2_Blocking(int) loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$poly2_Blocking(int) loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Shl loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$poly2_Blocking(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Shl loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ private static int $noinline$poly2_Blocking(int a) {
+ for (int i = 0; i < 10; i++) {
+ int k = 3 * i + 5;
+ a += k;
+
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$poly3() loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$poly3() loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$poly3() loop_optimization (after)
+ /// CHECK-DAG: <<Ini:i\d+>> IntConstant 12345 loop:none
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant -2146736968 loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Int>>,<<Ini>>] loop:none
+ /// CHECK-DAG: Return [<<Add>>] loop:none
+
+ /// CHECK-START: int Main.$noinline$poly3() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant -2146724623 loop:none
+ /// CHECK-DAG: Return [<<Int>>] loop:none
+
+ /// CHECK-START: int Main.$noinline$poly3() loop_optimization (after)
+ /// CHECK-NOT: Phi
+ private static int $noinline$poly3() {
+ int a = 12345;
+ for (int i = 0; i <= 10; i++) {
+ a += (2147483646 * i + 67890);
+ }
+
+ // Outer try catch does not block loop optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ return a;
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: int Main.$noinline$poly3_Blocking() loop_optimization (before)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: int Main.$noinline$poly3_Blocking() loop_optimization (before)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+
+ /// CHECK-START: int Main.$noinline$poly3_Blocking() loop_optimization (after)
+ /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ /// CHECK-DAG: Add loop:<<Loop>>
+ private static int $noinline$poly3_Blocking() {
+ int a = 12345;
+ for (int i = 0; i <= 10; i++) {
+ a += (2147483646 * i + 67890);
+
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ return a;
+ }
+
+ // Tests taken from 530-checker-loops5
+ private static void $noinline$loops5Tests() {
+ expectEquals(55, $noinline$poly1());
+ expectEquals(55, $noinline$poly1_Blocking());
+ expectEquals(185, $noinline$poly2(0));
+ expectEquals(185, $noinline$poly2_Blocking(0));
+ expectEquals(192, $noinline$poly2(7));
+ expectEquals(192, $noinline$poly2_Blocking(7));
+ expectEquals(-2146724623, $noinline$poly3());
+ expectEquals(-2146724623, $noinline$poly3_Blocking());
+ }
+
+ // Constants used for peel unroll tests.
+ private static final int LENGTH = 4 * 1024;
+ private static final int RESULT_POS = 4;
+
+ private static final void initIntArray(int[] a) {
+ for (int i = 0; i < a.length; i++) {
+ a[i] = i % 4;
+ }
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination(int[]) loop_optimization (after)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination(int[]) loop_optimization (before)
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Limit>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<Phi>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Get0>>,<<Get1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Array>>,<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination(int[]) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination(int[]) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Limit>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<Phi>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Get0>>,<<Get1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Array>>,<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none
+ //
+ /// CHECK-DAG: <<CheckA:z\d+>> GreaterThanOrEqual [<<IndAdd>>,<<Limit>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<IfA:v\d+>> If [<<Const0>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get0A:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<IndAddA:i\d+>> Add [<<IndAdd>>,<<Const1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get1A:i\d+>> ArrayGet [<<Array>>,<<IndAddA>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<AddA:i\d+>> Add [<<Get0A>>,<<Get1A>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Array>>,<<IndAdd>>,<<AddA>>] loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination(int[]) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination(int[]) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+ private static final void $noinline$unrollingLoadStoreElimination(int[] a) {
+ for (int i = 0; i < LENGTH - 2; i++) {
+ a[i] += a[i + 1];
+ }
+
+ // Outer try catch does not block loop optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination_Blocking(int[]) loop_optimization (after)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination_Blocking(int[]) loop_optimization (before)
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Limit>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<Phi>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Get0>>,<<Get1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Array>>,<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination_Blocking(int[]) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination_Blocking(int[]) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination_Blocking(int[]) loop_optimization (after)
+ /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none
+ /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Limit>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<Phi>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Add:i\d+>> Add [<<Get0>>,<<Get1>>] loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: ArraySet [<<Array>>,<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination_Blocking(int[]) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingLoadStoreElimination_Blocking(int[]) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+ private static final void $noinline$unrollingLoadStoreElimination_Blocking(int[] a) {
+ for (int i = 0; i < LENGTH - 2; i++) {
+ a[i] += a[i + 1];
+
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: If [<<Check>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+
+ // Each one of the three `for` loops has an `if`. The try catch has the 4th `if`.
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: If [<<Check>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: <<AddI:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ //
+ /// CHECK-DAG: If [<<Const0>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+
+ // Loop unrolling adds a 5th `if`. It is the one with `Const0` above.
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+ private static final void $noinline$unrollingInTheNest(int[] a, int[] b, int x) {
+ for (int k = 0; k < 16; k++) {
+ for (int j = 0; j < 16; j++) {
+ for (int i = 0; i < 128; i++) {
+ b[x]++;
+ a[i] = a[i] + 1;
+ }
+ }
+ }
+
+ // Outer try catch does not block loop optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_Blocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_Blocking(int[], int[], int) loop_optimization (before)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: If [<<Check>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ //
+ /// CHECK-DAG: Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+
+ // Each one of the three `for` loops has an `if`. The try catch has the 4th `if`.
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_Blocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_Blocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_Blocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_Blocking(int[], int[], int) loop_optimization (after)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: If [<<Check>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ //
+ /// CHECK-DAG: Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_Blocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_Blocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_Blocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+ private static final void $noinline$unrollingInTheNest_Blocking(int[] a, int[] b, int x) {
+ for (int k = 0; k < 16; k++) {
+ for (int j = 0; j < 16; j++) {
+ for (int i = 0; i < 128; i++) {
+ b[x]++;
+ a[i] = a[i] + 1;
+
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ }
+ }
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_TryCatchNotBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_TryCatchNotBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: If [<<Check>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ //
+ /// CHECK-DAG: Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+
+ // Each one of the three `for` loops has an `if`. The try catch has the 4th `if`.
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_TryCatchNotBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_TryCatchNotBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_TryCatchNotBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_TryCatchNotBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: If [<<Check>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: <<AddI:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ //
+ /// CHECK-DAG: If [<<Const0>>] loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
+
+ // Loop unrolling adds a 5th `if`. It is the one with `Const0` above.
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_TryCatchNotBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_TryCatchNotBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingInTheNest_TryCatchNotBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+ private static final void $noinline$unrollingInTheNest_TryCatchNotBlocking(int[] a, int[] b, int x) {
+ for (int k = 0; k < 16; k++) {
+ for (int j = 0; j < 16; j++) {
+ for (int i = 0; i < 128; i++) {
+ b[x]++;
+ a[i] = a[i] + 1;
+ }
+ // Try catch does not block the optimization in the innermost loop.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ }
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<XThres:i\d+>> IntConstant 100 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ //
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check2:z\d+>> GreaterThanOrEqual [<<Phi2>>,<<Limit>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check2>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<AddI2:i\d+>> Add [<<Phi2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check3:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check3>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<AddI3:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+
+ // Each one of the three `for` loops has an `if`. Plus an `if` inside the outer `for`. The try catch has the 5th `if`.
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<XThres:i\d+>> IntConstant 100 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ //
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check2:z\d+>> GreaterThanOrEqual [<<Phi2>>,<<Limit>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check2>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<AddI2:i\d+>> Add [<<Phi2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Const0>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: Add [<<AddI2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check3:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check3>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<AddI3:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Const0>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: Add [<<AddI3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+
+ // LoopOptimization adds two `if`s. One for each loop unrolling.
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+ private static final void $noinline$unrollingTwoLoopsInTheNest(int[] a, int[] b, int x) {
+ for (int k = 0; k < 128; k++) {
+ if (x > 100) {
+ for (int j = 0; j < 128; j++) {
+ a[x]++;
+ }
+ } else {
+ for (int i = 0; i < 128; i++) {
+ b[x]++;
+ }
+ }
+ }
+
+ // Outer try catch does not block loop optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OneBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OneBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<XThres:i\d+>> IntConstant 100 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ //
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check2:z\d+>> GreaterThanOrEqual [<<Phi2>>,<<Limit>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check2>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<AddI2:i\d+>> Add [<<Phi2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check3:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check3>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<AddI3:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+
+ // Each one of the three `for` loops has an `if`. Plus an `if` inside the outer `for`. The try catch has the 5th `if`.
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OneBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OneBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OneBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OneBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<XThres:i\d+>> IntConstant 100 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ //
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check2:z\d+>> GreaterThanOrEqual [<<Phi2>>,<<Limit>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check2>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ // Unrelated to the optimization itself, the try catch has an if.
+ /// CHECK-DAG: <<Get:z\d+>> StaticFieldGet field_name:Main.doThrow
+ /// CHECK-DAG: If [<<Get>>]
+ //
+ /// CHECK-DAG: <<AddI2:i\d+>> Add [<<Phi2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check3:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check3>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<AddI3:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Const0>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: Add [<<AddI3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+
+ // LoopOptimization adds two `if`s. One for each loop unrolling.
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OneBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OneBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OneBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+ private static final void $noinline$unrollingTwoLoopsInTheNest_OneBlocking(int[] a, int[] b, int x) {
+ for (int k = 0; k < 128; k++) {
+ if (x > 100) {
+ for (int j = 0; j < 128; j++) {
+ a[x]++;
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ } else {
+ for (int i = 0; i < 128; i++) {
+ b[x]++;
+ }
+ }
+ }
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OtherBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OtherBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<XThres:i\d+>> IntConstant 100 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ //
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check2:z\d+>> GreaterThanOrEqual [<<Phi2>>,<<Limit>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check2>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<AddI2:i\d+>> Add [<<Phi2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check3:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check3>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<AddI3:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+
+ // Each one of the three `for` loops has an `if`. Plus an `if` inside the outer `for`. The try catch has the 5th `if`.
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OtherBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OtherBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OtherBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OtherBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<XThres:i\d+>> IntConstant 100 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ //
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check2:z\d+>> GreaterThanOrEqual [<<Phi2>>,<<Limit>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check2>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<AddI2:i\d+>> Add [<<Phi2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Const0>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: Add [<<AddI2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check3:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check3>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<AddI3:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+
+ // LoopOptimization adds two `if`s. One for each loop unrolling.
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OtherBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OtherBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_OtherBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+ private static final void $noinline$unrollingTwoLoopsInTheNest_OtherBlocking(int[] a, int[] b, int x) {
+ for (int k = 0; k < 128; k++) {
+ if (x > 100) {
+ for (int j = 0; j < 128; j++) {
+ a[x]++;
+ }
+ } else {
+ for (int i = 0; i < 128; i++) {
+ b[x]++;
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ }
+ }
+ }
+
+ // Consistency check to see we haven't eliminated the try/catch.
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_BothBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: TryBoundary
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_BothBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<XThres:i\d+>> IntConstant 100 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ //
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check2:z\d+>> GreaterThanOrEqual [<<Phi2>>,<<Limit>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check2>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<AddI2:i\d+>> Add [<<Phi2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check3:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check3>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<AddI3:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+
+ // Each one of the three `for` loops has an `if`. Plus an `if` inside the outer `for`. The try catchs have the 5th and 6th `if`.
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_BothBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_BothBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_BothBlocking(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_BothBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
+ /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none
+ /// CHECK-DAG: <<XThres:i\d+>> IntConstant 100 loop:none
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none
+ //
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check2:z\d+>> GreaterThanOrEqual [<<Phi2>>,<<Limit>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check2>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ // Unrelated to the optimization itself, the try catch has an if.
+ /// CHECK-DAG: <<Get1:z\d+>> StaticFieldGet field_name:Main.doThrow
+ /// CHECK-DAG: If [<<Get1>>]
+ //
+ /// CHECK-DAG: <<AddI2:i\d+>> Add [<<Phi2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: <<Check3:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: If [<<Check3>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
+ /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
+ //
+ /// CHECK-DAG: <<AddI3:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_BothBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_BothBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.$noinline$unrollingTwoLoopsInTheNest_BothBlocking(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+ private static final void $noinline$unrollingTwoLoopsInTheNest_BothBlocking(int[] a, int[] b, int x) {
+ for (int k = 0; k < 128; k++) {
+ if (x > 100) {
+ for (int j = 0; j < 128; j++) {
+ a[x]++;
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ } else {
+ for (int i = 0; i < 128; i++) {
+ b[x]++;
+ // Try catch blocks optimizations.
+ try {
+ if (doThrow) {
+ $noinline$unreachable();
+ }
+ } catch (Error e) {
+ System.out.println("Not expected");
+ }
+ }
+ }
+ }
+ }
+
+ // Tests taken from 530-checker-peel-unroll
+ private static void $noinline$peelUnrollTests() {
+ int[] a = new int[LENGTH];
+ int[] b = new int[LENGTH];
+ initIntArray(a);
+ initIntArray(b);
+
+ $noinline$unrollingLoadStoreElimination(a);
+ $noinline$unrollingLoadStoreElimination_Blocking(a);
+ $noinline$unrollingInTheNest(a, b, RESULT_POS);
+ $noinline$unrollingInTheNest_Blocking(a, b, RESULT_POS);
+ $noinline$unrollingInTheNest_TryCatchNotBlocking(a, b, RESULT_POS);
+ $noinline$unrollingTwoLoopsInTheNest(a, b, RESULT_POS);
+ $noinline$unrollingTwoLoopsInTheNest_OneBlocking(a, b, RESULT_POS);
+ $noinline$unrollingTwoLoopsInTheNest_OtherBlocking(a, b, RESULT_POS);
+ $noinline$unrollingTwoLoopsInTheNest_BothBlocking(a, b, RESULT_POS);
+ }
+
+ public static void main(String[] args) {
+ // Use existing tests to show that the difference between having a try catch inside or outside
+ // the loop.
+ $noinline$loops4Tests();
+ $noinline$loops5Tests();
+ $noinline$peelUnrollTests();
+
+ System.out.println("passed");
+ }
+
+ private static void expectEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ private static void $noinline$unreachable() {
+ throw new Error("Unreachable");
+ }
+
+ private static boolean doThrow = false;
+}
diff --git a/test/530-checker-peel-unroll/src/Main.java b/test/530-checker-peel-unroll/src/Main.java
index aee32b7..f909af3 100644
--- a/test/530-checker-peel-unroll/src/Main.java
+++ b/test/530-checker-peel-unroll/src/Main.java
@@ -78,9 +78,15 @@
/// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> Add [<<Get0>>,<<Get1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [<<Array>>,<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none
- /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.unrollingLoadStoreElimination(int[]) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingLoadStoreElimination(int[]) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
/// CHECK-START: void Main.unrollingLoadStoreElimination(int[]) loop_optimization (after)
/// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none
@@ -103,9 +109,18 @@
/// CHECK-DAG: <<Get1A:i\d+>> ArrayGet [<<Array>>,<<IndAddA>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<AddA:i\d+>> Add [<<Get0A>>,<<Get1A>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [<<Array>>,<<IndAdd>>,<<AddA>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none
- /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.unrollingLoadStoreElimination(int[]) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingLoadStoreElimination(int[]) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
private static final void unrollingLoadStoreElimination(int[] a) {
for (int i = 0; i < LENGTH - 2; i++) {
a[i] += a[i + 1];
@@ -124,9 +139,14 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none
- /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.unrollingSwitch(int[]) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingSwitch(int[]) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
/// CHECK-START: void Main.unrollingSwitch(int[]) loop_optimization (after)
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
@@ -144,9 +164,16 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<AddI>>,<<Const1>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none
- /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.unrollingSwitch(int[]) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingSwitch(int[]) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
private static final void unrollingSwitch(int[] a) {
for (int i = 0; i < LENGTH; i++) {
switch (i % 3) {
@@ -173,9 +200,16 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none
- /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.unrollingSwapElements(int[]) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingSwapElements(int[]) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
/// CHECK-START: void Main.unrollingSwapElements(int[]) loop_optimization (after)
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
@@ -197,9 +231,20 @@
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<AddI>>,<<Const1>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none
- /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.unrollingSwapElements(int[]) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingSwapElements(int[]) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
private static final void unrollingSwapElements(int[] array) {
for (int i = 0; i < LENGTH - 2; i++) {
if (array[i] > array[i + 1]) {
@@ -225,9 +270,21 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none
- /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none
+
+ // We have two other `ArrayGet` before the `If` that appears in the CHECK-DAG above.
+ /// CHECK-START: void Main.unrollingRInnerproduct(double[][], double[][], double[][], int, int) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingRInnerproduct(double[][], double[][], double[][], int, int) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
/// CHECK-START: void Main.unrollingRInnerproduct(double[][], double[][], double[][], int, int) loop_optimization (after)
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
@@ -251,9 +308,25 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: Add [<<AddI>>,<<Const1>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none
- /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: void Main.unrollingRInnerproduct(double[][], double[][], double[][], int, int) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingRInnerproduct(double[][], double[][], double[][], int, int) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
private static final void unrollingRInnerproduct(double[][] result,
double[][] a,
double[][] b,
@@ -284,11 +357,24 @@
/// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
/// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
/// CHECK-DAG: Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop2>>
- //
- /// CHECK-NOT: ArrayGet
- /// CHECK-NOT: ArraySet
+
+ // Each one of the three `for` loops has an `if`.
+ /// CHECK-START: void Main.unrollingInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
/// CHECK-NOT: If
+ /// CHECK-START: void Main.unrollingInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+
/// CHECK-START: void Main.unrollingInTheNest(int[], int[], int) loop_optimization (after)
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
@@ -309,10 +395,28 @@
/// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
/// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>>
/// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>>
- //
- /// CHECK-NOT: ArrayGet
- /// CHECK-NOT: ArraySet
+
+ // Loop unrolling adds a 4th `if`. It is the one with `Const0` above.
+ /// CHECK-START: void Main.unrollingInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
/// CHECK-NOT: If
+
+ /// CHECK-START: void Main.unrollingInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
private static final void unrollingInTheNest(int[] a, int[] b, int x) {
for (int k = 0; k < 16; k++) {
for (int j = 0; j < 16; j++) {
@@ -349,11 +453,25 @@
/// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
/// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
/// CHECK-DAG: <<AddI3:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
- //
- /// CHECK-NOT: ArrayGet
- /// CHECK-NOT: ArraySet
+
+ // Each one of the three `for` loops has an `if`. Plus an `if` inside the outer `for`.
+ /// CHECK-START: void Main.unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
/// CHECK-NOT: If
+ /// CHECK-START: void Main.unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
+
/// CHECK-START: void Main.unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (after)
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none
@@ -382,10 +500,30 @@
/// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>>
/// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>>
/// CHECK-DAG: Add [<<AddI3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>>
- //
- /// CHECK-NOT: ArrayGet
- /// CHECK-NOT: ArraySet
+
+ // LoopOptimization adds two `if`s. One for each loop unrolling.
+ /// CHECK-START: void Main.unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
/// CHECK-NOT: If
+
+ /// CHECK-START: void Main.unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
private static final void unrollingTwoLoopsInTheNest(int[] a, int[] b, int x) {
for (int k = 0; k < 128; k++) {
if (x > 100) {
@@ -423,7 +561,14 @@
/// CHECK-DAG: <<ZCheck:i\d+>> DivZeroCheck [<<STAdd>>] env:[[<<PhiS>>,<<PhiT>>,<<STAdd>>,<<Const1>>,_,<<Array>>]] loop:none
/// CHECK-DAG: <<Div:i\d+>> Div [<<Const1>>,<<ZCheck>>] loop:none
/// CHECK-DAG: Return [<<Div>>] loop:none
+
+ /// CHECK-START: int Main.unrollingSimpleLiveOuts(int[]) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
/// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: int Main.unrollingSimpleLiveOuts(int[]) loop_optimization (before)
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
/// CHECK-START: int Main.unrollingSimpleLiveOuts(int[]) loop_optimization (after)
@@ -461,8 +606,17 @@
/// CHECK-DAG: <<ZCheck:i\d+>> DivZeroCheck [<<STAdd>>] env:[[<<RetPhiS>>,<<RetPhiT>>,<<STAdd>>,<<Const1>>,_,<<Array>>]] loop:none
/// CHECK-DAG: <<Div:i\d+>> Div [<<Const1>>,<<ZCheck>>] loop:none
/// CHECK-DAG: Return [<<Div>>] loop:none
- //
+
+ /// CHECK-START: int Main.unrollingSimpleLiveOuts(int[]) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
/// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: int Main.unrollingSimpleLiveOuts(int[]) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
private static final int unrollingSimpleLiveOuts(int[] a) {
int s = 1;
@@ -502,8 +656,14 @@
/// CHECK-DAG: ArraySet [<<Array>>,<<PhiI>>,<<AddArr>>] loop:<<Loop1>> outer_loop:<<Loop0>>
//
/// CHECK-DAG: Add [<<OutPhiJ>>,<<Const1>>] loop:<<Loop0>> outer_loop:none
- //
+
+ /// CHECK-START: int Main.unrollingLiveOutsNested(int[]) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
/// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: int Main.unrollingLiveOutsNested(int[]) loop_optimization (before)
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
/// CHECK-START: int Main.unrollingLiveOutsNested(int[]) loop_optimization (after)
@@ -545,8 +705,17 @@
//
/// CHECK-DAG: <<RetAdd:i\d+>> Add [<<OutPhiS>>,<<OutPhiT>>] loop:none
/// CHECK-DAG: Return [<<RetAdd>>] loop:none
- //
+
+ /// CHECK-START: int Main.unrollingLiveOutsNested(int[]) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
/// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: int Main.unrollingLiveOutsNested(int[]) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
private static final int unrollingLiveOutsNested(int[] a) {
int s = 1;
@@ -566,16 +735,21 @@
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: InstanceOf loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: InstanceOf
+
+ /// CHECK-START: void Main.unrollingInstanceOf(int[], java.lang.Object[]) loop_optimization (before)
+ /// CHECK: InstanceOf
+ /// CHECK-NOT: InstanceOf
/// CHECK-START: void Main.unrollingInstanceOf(int[], java.lang.Object[]) loop_optimization (after)
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: InstanceOf loop:<<Loop>> outer_loop:none
/// CHECK-DAG: InstanceOf loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: InstanceOf
+
+ /// CHECK-START: void Main.unrollingInstanceOf(int[], java.lang.Object[]) loop_optimization (after)
+ /// CHECK: InstanceOf
+ /// CHECK: InstanceOf
+ /// CHECK-NOT: InstanceOf
public void unrollingInstanceOf(int[] a, Object[] obj_array) {
for (int i = 0; i < LENGTH_B; i++) {
if (obj_array[i] instanceof Integer) {
@@ -588,16 +762,21 @@
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: DivZeroCheck loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: DivZeroCheck
+
+ /// CHECK-START: void Main.unrollingDivZeroCheck(int[], int) loop_optimization (before)
+ /// CHECK: DivZeroCheck
+ /// CHECK-NOT: DivZeroCheck
/// CHECK-START: void Main.unrollingDivZeroCheck(int[], int) loop_optimization (after)
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: DivZeroCheck loop:<<Loop>> outer_loop:none
/// CHECK-DAG: DivZeroCheck loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: DivZeroCheck
+
+ /// CHECK-START: void Main.unrollingDivZeroCheck(int[], int) loop_optimization (after)
+ /// CHECK: DivZeroCheck
+ /// CHECK: DivZeroCheck
+ /// CHECK-NOT: DivZeroCheck
public void unrollingDivZeroCheck(int[] a, int r) {
for (int i = 0; i < LENGTH_B; i++) {
a[i] += a[i] / r;
@@ -608,16 +787,21 @@
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: TypeConversion loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: TypeConversion
+
+ /// CHECK-START: void Main.unrollingTypeConversion(int[], double[]) loop_optimization (before)
+ /// CHECK: TypeConversion
+ /// CHECK-NOT: TypeConversion
/// CHECK-START: void Main.unrollingTypeConversion(int[], double[]) loop_optimization (after)
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: TypeConversion loop:<<Loop>> outer_loop:none
/// CHECK-DAG: TypeConversion loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: TypeConversion
+
+ /// CHECK-START: void Main.unrollingTypeConversion(int[], double[]) loop_optimization (after)
+ /// CHECK: TypeConversion
+ /// CHECK: TypeConversion
+ /// CHECK-NOT: TypeConversion
public void unrollingTypeConversion(int[] a, double[] b) {
for (int i = 0; i < LENGTH_B; i++) {
a[i] = (int) b[i];
@@ -634,16 +818,21 @@
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: CheckCast loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: CheckCast
+
+ /// CHECK-START: void Main.unrollingCheckCast(int[], java.lang.Object) loop_optimization (before)
+ /// CHECK: CheckCast
+ /// CHECK-NOT: CheckCast
/// CHECK-START: void Main.unrollingCheckCast(int[], java.lang.Object) loop_optimization (after)
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none
/// CHECK-DAG: Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: CheckCast loop:<<Loop>> outer_loop:none
/// CHECK-DAG: CheckCast loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: CheckCast
+
+ /// CHECK-START: void Main.unrollingCheckCast(int[], java.lang.Object) loop_optimization (after)
+ /// CHECK: CheckCast
+ /// CHECK: CheckCast
+ /// CHECK-NOT: CheckCast
public void unrollingCheckCast(int[] a, Object o) {
for (int i = 0; i < LENGTH_B; i++) {
if (((SubMain)o) == o) {
@@ -664,10 +853,22 @@
/// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> Add [<<Get0>>,<<Get1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [<<Array>>,<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none
- //
+
+ /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (before)
+ /// CHECK: Phi
/// CHECK-NOT: Phi
+
+ /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (before)
+ /// CHECK: If
/// CHECK-NOT: If
+
+ /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
/// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (before)
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
/// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (after)
@@ -676,10 +877,22 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
- //
+
+ /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (after)
+ /// CHECK: Phi
/// CHECK-NOT: Phi
+
+ /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (after)
+ /// CHECK: If
/// CHECK-NOT: If
+
+ /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
/// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (after)
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
private static final void noUnrollingOddTripCount(int[] a) {
for (int i = 0; i < LENGTH - 1; i++) {
@@ -699,9 +912,24 @@
/// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<Add:i\d+>> Add [<<Get0>>,<<Get1>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [<<Array>>,<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none
- //
+
+ /// CHECK-START: void Main.noUnrollingNotKnownTripCount(int[], int) loop_optimization (before)
+ /// CHECK: Phi
/// CHECK-NOT: Phi
+
+ // One `if` for the `for` loop, and another one for a deoptimize.
+ /// CHECK-START: void Main.noUnrollingNotKnownTripCount(int[], int) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.noUnrollingNotKnownTripCount(int[], int) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
/// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.noUnrollingNotKnownTripCount(int[], int) loop_optimization (before)
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
/// CHECK-START: void Main.noUnrollingNotKnownTripCount(int[], int) loop_optimization (after)
@@ -710,9 +938,23 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
- //
+
+ /// CHECK-START: void Main.noUnrollingNotKnownTripCount(int[], int) loop_optimization (after)
+ /// CHECK: Phi
/// CHECK-NOT: Phi
+
+ /// CHECK-START: void Main.noUnrollingNotKnownTripCount(int[], int) loop_optimization (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.noUnrollingNotKnownTripCount(int[], int) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
/// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.noUnrollingNotKnownTripCount(int[], int) loop_optimization (after)
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
private static final void noUnrollingNotKnownTripCount(int[] a, int n) {
for (int i = 0; i < n; i++) {
@@ -732,9 +974,15 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: If
- /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.peelingSimple(int[], boolean) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.peelingSimple(int[], boolean) loop_optimization (before)
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
/// CHECK-START: void Main.peelingSimple(int[], boolean) loop_optimization (after)
/// CHECK-DAG: <<Param:z\d+>> ParameterValue loop:none
@@ -754,9 +1002,18 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: If
- /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.peelingSimple(int[], boolean) loop_optimization (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.peelingSimple(int[], boolean) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
/// CHECK-START: void Main.peelingSimple(int[], boolean) dead_code_elimination$final (after)
/// CHECK-DAG: <<Param:z\d+>> ParameterValue loop:none
@@ -772,11 +1029,25 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: GreaterThanOrEqual
- /// CHECK-NOT: If
- /// CHECK-NOT: ArrayGet
- /// CHECK-NOT: ArraySet
+
+ /// CHECK-START: void Main.peelingSimple(int[], boolean) dead_code_elimination$final (after)
+ /// CHECK: GreaterThanOrEqual
+ /// CHECK-NOT: GreaterThanOrEqual
+
+ /// CHECK-START: void Main.peelingSimple(int[], boolean) dead_code_elimination$final (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+
+ /// CHECK-START: void Main.peelingSimple(int[], boolean) dead_code_elimination$final (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.peelingSimple(int[], boolean) dead_code_elimination$final (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK-NOT: ArraySet
private static final void peelingSimple(int[] a, boolean f) {
for (int i = 0; i < LENGTH; i++) {
if (f) {
@@ -808,8 +1079,13 @@
/// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: If [<<Check>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
- //
- /// CHECK-NOT: If [<<Eq>>] loop:<<Loop>> outer_loop:none
+
+ // There's a 3rd `if` due to bounds checks.
+ /// CHECK-START: void Main.peelingAddInts(int[]) dead_code_elimination$final (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
private static final void peelingAddInts(int[] a) {
for (int i = 0; a != null && i < a.length; i++) {
a[i] += 1;
@@ -830,8 +1106,16 @@
/// CHECK-DAG: ArraySet loop:<<Loop1>> outer_loop:<<Loop0>>
/// CHECK-DAG: <<IndAdd1:i\d+>> Add [<<Phi1>>,<<Const1>>] loop:<<Loop1>> outer_loop:<<Loop0>>
/// CHECK-DAG: <<IndAdd0:i\d+>> Add [<<Phi0>>,<<Const1>>] loop:<<Loop0>> outer_loop:none
- //
+
+ // The two loops have an `if`. The 3rd `if` is the explicit one in the innermost loop.
+ /// CHECK-START: void Main.peelingBreakFromNest(int[], boolean) loop_optimization (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
/// CHECK-NOT: If
+
+ /// CHECK-START: void Main.peelingBreakFromNest(int[], boolean) loop_optimization (before)
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
/// CHECK-START: void Main.peelingBreakFromNest(int[], boolean) dead_code_elimination$final (after)
@@ -850,8 +1134,16 @@
/// CHECK-DAG: ArraySet loop:<<Loop1>> outer_loop:<<Loop0>>
/// CHECK-DAG: <<IndAdd1:i\d+>> Add [<<Phi1>>,<<Const1>>] loop:<<Loop1>> outer_loop:<<Loop0>>
/// CHECK-DAG: <<IndAdd0:i\d+>> Add [<<Phi0>>,<<Const1>>] loop:<<Loop0>> outer_loop:none
- //
+
+ /// CHECK-START: void Main.peelingBreakFromNest(int[], boolean) dead_code_elimination$final (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
/// CHECK-NOT: If
+
+ /// CHECK-START: void Main.peelingBreakFromNest(int[], boolean) dead_code_elimination$final (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
private static final void peelingBreakFromNest(int[] a, boolean f) {
outer:
@@ -873,7 +1165,9 @@
/// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: If [<<Check>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none
- //
+
+ /// CHECK-START: int Main.peelingHoistOneControl(int) loop_optimization (before)
+ /// CHECK: If
/// CHECK-NOT: If
/// CHECK-START: int Main.peelingHoistOneControl(int) dead_code_elimination$final (after)
@@ -886,8 +1180,15 @@
//
// Check that the loop has no instruction except SuspendCheck and Goto (indefinite loop).
/// CHECK-NOT: loop:<<Loop>> outer_loop:none
+
+ /// CHECK-START: int Main.peelingHoistOneControl(int) dead_code_elimination$final (after)
+ /// CHECK: If
/// CHECK-NOT: If
+
+ /// CHECK-START: int Main.peelingHoistOneControl(int) dead_code_elimination$final (after)
/// CHECK-NOT: Phi
+
+ /// CHECK-START: int Main.peelingHoistOneControl(int) dead_code_elimination$final (after)
/// CHECK-NOT: Add
private static final int peelingHoistOneControl(int x) {
int i = 0;
@@ -902,11 +1203,17 @@
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: If loop:<<Loop>> outer_loop:none
/// CHECK-DAG: If loop:<<Loop>> outer_loop:none
- //
+
/// CHECK-START: int Main.peelingHoistOneControl(int, int) dead_code_elimination$final (after)
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: If loop:<<Loop>> outer_loop:none
- /// CHECK-NOT: If loop:<<Loop>> outer_loop:none
+
+ // One `if` inside the loop (the one no longer invariant), two outside of it.
+ /// CHECK-START: int Main.peelingHoistOneControl(int, int) dead_code_elimination$final (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
private static final int peelingHoistOneControl(int x, int y) {
while (true) {
if (x == 0)
@@ -922,11 +1229,18 @@
/// CHECK-DAG: If loop:<<Loop>> outer_loop:none
/// CHECK-DAG: If loop:<<Loop>> outer_loop:none
/// CHECK-DAG: If loop:<<Loop>> outer_loop:none
- //
+
/// CHECK-START: int Main.peelingHoistTwoControl(int, int, int) dead_code_elimination$final (after)
/// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: If loop:<<Loop>> outer_loop:none
- /// CHECK-NOT: If loop:<<Loop>> outer_loop:none
+
+ // One `if` inside the loop (the one no longer invariant), three outside of it.
+ /// CHECK-START: int Main.peelingHoistTwoControl(int, int, int) dead_code_elimination$final (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
private static final int peelingHoistTwoControl(int x, int y, int z) {
while (true) {
if (x == 0)
@@ -948,8 +1262,14 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
- //
+
+ /// CHECK-START: void Main.unrollingFull(int[]) loop_optimization (before)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
/// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingFull(int[]) loop_optimization (before)
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
/// CHECK-START: void Main.unrollingFull(int[]) loop_optimization (after)
@@ -970,8 +1290,20 @@
/// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none
/// CHECK-DAG: If [<<Const1>>] loop:<<Loop>> outer_loop:none
- //
+
+ /// CHECK-START: void Main.unrollingFull(int[]) loop_optimization (after)
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
+ /// CHECK: ArrayGet
/// CHECK-NOT: ArrayGet
+
+ /// CHECK-START: void Main.unrollingFull(int[]) loop_optimization (after)
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
+ /// CHECK: ArraySet
/// CHECK-NOT: ArraySet
private static final void unrollingFull(int[] a) {
for (int i = 0; i < 2; i++) {
diff --git a/test/731-bounds-check-slow-path/Android.bp b/test/731-bounds-check-slow-path/Android.bp
new file mode 100644
index 0000000..bc9e84b
--- /dev/null
+++ b/test/731-bounds-check-slow-path/Android.bp
@@ -0,0 +1,40 @@
+// Generated by `regen-test-files`. Do not edit manually.
+
+// Build rules for ART run-test `731-bounds-check-slow-path`.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "art_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["art_license"],
+}
+
+// Test's Dex code.
+java_test {
+ name: "art-run-test-731-bounds-check-slow-path",
+ defaults: ["art-run-test-defaults"],
+ test_config_template: ":art-run-test-target-template",
+ srcs: ["src/**/*.java"],
+ data: [
+ ":art-run-test-731-bounds-check-slow-path-expected-stdout",
+ ":art-run-test-731-bounds-check-slow-path-expected-stderr",
+ ],
+}
+
+// Test's expected standard output.
+genrule {
+ name: "art-run-test-731-bounds-check-slow-path-expected-stdout",
+ out: ["art-run-test-731-bounds-check-slow-path-expected-stdout.txt"],
+ srcs: ["expected-stdout.txt"],
+ cmd: "cp -f $(in) $(out)",
+}
+
+// Test's expected standard error.
+genrule {
+ name: "art-run-test-731-bounds-check-slow-path-expected-stderr",
+ out: ["art-run-test-731-bounds-check-slow-path-expected-stderr.txt"],
+ srcs: ["expected-stderr.txt"],
+ cmd: "cp -f $(in) $(out)",
+}
diff --git a/test/731-bounds-check-slow-path/expected-stderr.txt b/test/731-bounds-check-slow-path/expected-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/731-bounds-check-slow-path/expected-stderr.txt
diff --git a/test/731-bounds-check-slow-path/expected-stdout.txt b/test/731-bounds-check-slow-path/expected-stdout.txt
new file mode 100644
index 0000000..f3ed3fd
--- /dev/null
+++ b/test/731-bounds-check-slow-path/expected-stdout.txt
@@ -0,0 +1,3 @@
+i17 i18 b = 297,33580744,0
+l i19 i20 = 146,172,60
+i16 b i17 = -848052580,0,401
diff --git a/test/731-bounds-check-slow-path/info.txt b/test/731-bounds-check-slow-path/info.txt
new file mode 100644
index 0000000..0129f67
--- /dev/null
+++ b/test/731-bounds-check-slow-path/info.txt
@@ -0,0 +1,3 @@
+Regression tests for x86-64 bug in bounds check slow path that resulted
+in a live register being clobbered when throwing AIOOBE. The value must
+be correctly preserved for a catch handler in the same method.
diff --git a/test/731-bounds-check-slow-path/src/Main.java b/test/731-bounds-check-slow-path/src/Main.java
new file mode 100644
index 0000000..76b5723
--- /dev/null
+++ b/test/731-bounds-check-slow-path/src/Main.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String args[]) {
+ Test227365246 test227365246 = new Test227365246();
+ test227365246.$noinline$mainTest(args);
+
+ Test216608614 test216608614 = new Test216608614();
+ test216608614.$noinline$mainTest(args);
+
+ Test216629762 test216629762 = new Test216629762();
+ test216629762.$noinline$mainTest(args);
+ }
+}
+
+class Test227365246 {
+ int N = 400;
+ int iFld;
+
+ void $noinline$mainTest(String[] strArr1) {
+ int i17, i18 = 5788, i19, i21, i22 = 127, i23;
+ byte[] byArr = new byte[N];
+ for (i17 = 14; 297 > i17; ++i17)
+ for (int ax$2 = 151430; ax$2 < 235417; ax$2 += 2) {}
+ try {
+ for (i19 = 4; 179 > i19; ++i19) {
+ i18 *= i18;
+ for (i21 = 1; i21 < 58; i21++)
+ for (i23 = i21; 1 + 400 > i23; i23++) {
+ byArr[i23] -= i22;
+ i18 += i23;
+ switch (i19 % 5) {
+ case 107:
+ i19 >>= iFld;
+ }
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException exc1) {
+ }
+ System.out.println("i17 i18 b = " + i17 + "," + i18 + "," + 0);
+ }
+}
+
+class Test216608614 {
+ int N = 400;
+ long lFld;
+ double dFld;
+ int iArrFld[]=new int[N];
+ void $noinline$mainTest(String[] strArr1) {
+ // Note: The original bug report started with `l=-1213929899L` but this took
+ // too long when running with interpreter without JIT and we want to allow
+ // this test to run for all configurations. Starting with `l=-1000000L` was
+ // enough to allow JIT to compile the method for OSR and trigger the bug on host.
+ long l=-1000000L;
+ int i19= 46, i20=100, i21, i22=13, i25;
+ try {
+ do
+ for (; i19 < 172; ++i19)
+ lFld = (long) dFld;
+ while (++l < 146);
+ for (i21 = 8;; ++i21)
+ for (i25 = 1; i25 < 2; i25++) {
+ i20 = i22 % 1650388388;
+ i20 = iArrFld[i21];
+ i22 = 60;
+ }
+ } catch (ArrayIndexOutOfBoundsException exc1) {
+ } finally {
+ }
+ System.out.println("l i19 i20 = " + l + "," + i19 + "," + i20);
+ }
+}
+
+class Test216629762 {
+ static int N = 400;
+ int iFld=29275;
+ volatile double dFld;
+ static long lArrFld[][]=new long[N][N];
+
+ void $noinline$mainTest(String[] strArr1) {
+ int i8, i10=181, i11, i12=-57574, i13=69, i15= 6, i16= 186, i17= 227;
+ try {
+ for (i11 = 6; i11 < 278 + 400; ++i11)
+ i12 *= iFld;
+ for (;; i13++) {
+ i10 /= i10;
+ i16 += i15;
+ lArrFld[i13][i15] >>= 31616;
+ for (i17 = 1; i17 < 1 + 400; i17++)
+ dFld += dFld;
+ }
+ }
+ catch (ArrayIndexOutOfBoundsException exc2) {
+ i16 += i12;
+ }
+ System.out.println("i16 b i17 = " + i16 + "," + 0 + "," + i17);
+ }
+}
diff --git a/test/odsign/Android.bp b/test/odsign/Android.bp
index c3cccd3..511f5a1 100644
--- a/test/odsign/Android.bp
+++ b/test/odsign/Android.bp
@@ -16,14 +16,7 @@
default_applicable_licenses: ["art_license"],
}
-soong_config_module_type_import {
- from: "art/build/SoongConfig.bp",
- module_types: [
- "art_module_java_defaults",
- ],
-}
-
-art_module_java_defaults {
+java_defaults {
name: "odsign_e2e_tests_defaults",
defaults: ["art_module_source_build_java_defaults"],
srcs: ["test-src/**/*.java"],
@@ -32,14 +25,16 @@
"cts-install-lib-host",
"frameworks-base-hostutils",
],
- data: [
- ":odsign_e2e_test_app",
- ],
}
java_test_host {
name: "odsign_e2e_tests",
defaults: ["odsign_e2e_tests_defaults"],
+ // TODO(b/228838581): Do not add `data` to the defaults unless the bug is
+ // fixed.
+ data: [
+ ":odsign_e2e_test_app",
+ ],
test_config: "odsign-e2e-tests.xml",
test_suites: [
"general-tests",
@@ -50,6 +45,11 @@
java_test_host {
name: "odsign_e2e_tests_full",
defaults: ["odsign_e2e_tests_defaults"],
+ // TODO(b/228838581): Do not add `data` to the defaults unless the bug is
+ // fixed.
+ data: [
+ ":odsign_e2e_test_app",
+ ],
test_config: "odsign-e2e-tests-full.xml",
test_suites: [
"general-tests",