!2768 Remove NewArray/StoreArray

Merge pull request !2768 from Mikhail Ivanov/20372-remove-newarray-storearray-after-optimizestringconcat
This commit is contained in:
openharmony_ci 2024-11-08 18:05:40 +00:00 committed by Gitee
commit 6f7c20c102
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
8 changed files with 257 additions and 52 deletions

View File

@ -1216,8 +1216,8 @@ InlinedGraph Inlining::BuildGraph(InlineContext *ctx, CallInst *callInst, CallIn
auto objectTypeApplied = graphInl->RunPass<ObjectTypeCheckElimination>();
if (peepholeApplied || objectTypeApplied) {
graphInl->RunPass<BranchElimination>();
graphInl->RunPass<Cleanup>();
}
graphInl->RunPass<Cleanup>(false);
graphInl->RunPass<OptimizeStringConcat>();
graphInl->RunPass<SimplifyStringBuilder>();

View File

@ -31,7 +31,10 @@
namespace ark::compiler {
OptimizeStringConcat::OptimizeStringConcat(Graph *graph) : Optimization(graph) {}
OptimizeStringConcat::OptimizeStringConcat(Graph *graph)
: Optimization(graph), arrayElements_ {graph->GetAllocator()->Adapter()}
{
}
RuntimeInterface::IdType GetStringBuilderClassId(Graph *graph)
{
@ -80,33 +83,6 @@ void OptimizeStringConcat::InvalidateAnalyses()
GetGraph()->InvalidateAnalysis<AliasAnalysis>();
}
Inst *GetPhiConstantInput(Inst *phi)
{
ASSERT(phi->GetInputsCount() == 2U); // NOLINT(readability-magic-numbers)
ASSERT(phi->GetDataFlowInput(1)->IsPhi());
auto inputInst0 = phi->GetDataFlowInput(0);
if (inputInst0->IsConst()) {
return inputInst0;
}
if (inputInst0->IsPhi()) {
return GetPhiConstantInput(inputInst0);
}
UNREACHABLE();
}
Inst *GetArrayLength(Inst *newArray)
{
ASSERT(newArray->GetInputsCount() > 1);
auto inputInst1 = newArray->GetDataFlowInput(1);
if (inputInst1->IsConst()) {
return inputInst1;
}
if (inputInst1->IsPhi()) {
return GetPhiConstantInput(inputInst1);
}
UNREACHABLE();
}
Inst *CreateInstructionStringBuilderInstance(Graph *graph, uint32_t pc, SaveStateInst *saveState)
{
auto runtime = graph->GetRuntime();
@ -188,11 +164,8 @@ void OptimizeStringConcat::FixBrokenSaveStates(Inst *source, Inst *target)
}
}
void OptimizeStringConcat::CreateAppendArgsIntrinsics(Inst *instance, Inst *args, uint64_t arrayLengthValue,
SaveStateInst *saveState)
void OptimizeStringConcat::CreateAppendArgsIntrinsic(Inst *instance, Inst *arg, SaveStateInst *saveState)
{
for (uint64_t index = 0; index < arrayLengthValue; ++index) {
auto arg = CreateLoadArray(GetGraph(), args, index);
auto appendIntrinsic = CreateStringBuilderAppendStringIntrinsic(GetGraph(), instance, arg, saveState);
InsertBeforeWithInputs(appendIntrinsic, saveState);
@ -202,6 +175,21 @@ void OptimizeStringConcat::CreateAppendArgsIntrinsics(Inst *instance, Inst *args
COMPILER_LOG(DEBUG, OPTIMIZE_STRING_CONCAT)
<< "Insert StringBuilder.append intrinsic (id=" << appendIntrinsic->GetId() << ")";
}
void OptimizeStringConcat::CreateAppendArgsIntrinsics(Inst *instance, SaveStateInst *saveState)
{
for (auto arg : arrayElements_) {
CreateAppendArgsIntrinsic(instance, arg, saveState);
}
}
void OptimizeStringConcat::CreateAppendArgsIntrinsics(Inst *instance, Inst *args, uint64_t arrayLengthValue,
SaveStateInst *saveState)
{
for (uint64_t index = 0; index < arrayLengthValue; ++index) {
auto arg = CreateLoadArray(GetGraph(), args, index);
CreateAppendArgsIntrinsic(instance, arg, saveState);
}
}
Inst *CreateSafePoint(Graph *graph, uint32_t pc, SaveStateInst *saveState)
@ -278,6 +266,24 @@ BasicBlock *OptimizeStringConcat::CreateAppendArgsLoop(Inst *instance, Inst *str
return postExit;
}
bool OptimizeStringConcat::HasStoreArrayUsersOnly(Inst *newArray, Inst *removable)
{
ASSERT(newArray->GetOpcode() == Opcode::NewArray);
MarkerHolder visited {newArray->GetBasicBlock()->GetGraph()};
bool found = HasUserRecursively(newArray, visited.GetMarker(), [newArray, removable](auto &user) {
auto userInst = user.GetInst();
auto isSaveState = userInst->IsSaveState();
auto isCheck = userInst->IsCheck();
auto isStoreArray = userInst->GetOpcode() == Opcode::StoreArray && userInst->GetDataFlowInput(0) == newArray;
bool isRemovable = userInst == removable;
return !isSaveState && !isCheck && !isStoreArray && !isRemovable;
});
ResetUserMarkersRecursively(newArray, visited.GetMarker());
return !found;
}
void OptimizeStringConcat::ReplaceStringConcatWithStringBuilderAppend(Inst *concatCall)
{
// Input:
@ -311,16 +317,17 @@ void OptimizeStringConcat::ReplaceStringConcatWithStringBuilderAppend(Inst *conc
auto toStringCall = CreateStringBuilderToStringIntrinsic(GetGraph(), instance, concatCall->GetSaveState());
if (args->GetOpcode() == Opcode::NewArray) {
auto arrayLength = GetArrayLength(args);
auto arrayLength = GetArrayLengthConstant(args);
bool collected = args->GetOpcode() == Opcode::NewArray && CollectArrayElements(args, arrayElements_);
if (collected) {
CreateAppendArgsIntrinsics(instance, concatCall->GetSaveState());
InsertBeforeWithSaveState(toStringCall, concatCall->GetSaveState());
} else if (args->GetOpcode() == Opcode::NewArray && arrayLength != nullptr) {
CreateAppendArgsIntrinsics(instance, args, arrayLength->CastToConstant()->GetIntValue(),
concatCall->GetSaveState());
InsertBeforeWithSaveState(toStringCall, concatCall->GetSaveState());
COMPILER_LOG(DEBUG, OPTIMIZE_STRING_CONCAT) << "Replace String.concat call (id=" << concatCall->GetId()
<< ") with StringBuilder instance (id=" << instance->GetId() << ")";
} else {
auto arrayLength = CreateLenArray(GetGraph(), args);
arrayLength = CreateLenArray(GetGraph(), args);
concatCall->GetSaveState()->InsertBefore(arrayLength);
auto postExit = CreateAppendArgsLoop(instance, str, args, arrayLength->CastToLenArray(), concatCall);
@ -329,10 +336,9 @@ void OptimizeStringConcat::ReplaceStringConcatWithStringBuilderAppend(Inst *conc
InvalidateBlocksOrderAnalyzes(GetGraph());
GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
}
COMPILER_LOG(DEBUG, OPTIMIZE_STRING_CONCAT) << "Replace String.concat call (id=" << concatCall->GetId()
<< ") with StringBuilder instance (id=" << instance->GetId() << ")";
}
FixBrokenSaveStates(instance, toStringCall);
@ -342,6 +348,11 @@ void OptimizeStringConcat::ReplaceStringConcatWithStringBuilderAppend(Inst *conc
if (concatCall->GetInput(0).GetInst()->IsCheck()) {
concatCall->GetInput(0).GetInst()->ClearFlag(inst_flags::NO_DCE);
}
if (collected && HasStoreArrayUsersOnly(args, concatCall)) {
CleanupStoreArrayInstructions(args);
args->ClearFlag(inst_flags::NO_DCE);
}
}
} // namespace ark::compiler

View File

@ -49,14 +49,18 @@ public:
void InvalidateAnalyses() override;
private:
void CreateAppendArgsIntrinsic(Inst *instance, Inst *arg, SaveStateInst *saveState);
void CreateAppendArgsIntrinsics(Inst *instance, SaveStateInst *saveState);
void CreateAppendArgsIntrinsics(Inst *instance, Inst *args, uint64_t arrayLengthValue, SaveStateInst *saveState);
BasicBlock *CreateAppendArgsLoop(Inst *instance, Inst *str, Inst *args, LengthMethodInst *arrayLength,
Inst *concatCall);
void FixBrokenSaveStates(Inst *source, Inst *target);
bool HasStoreArrayUsersOnly(Inst *newArray, Inst *removable);
void ReplaceStringConcatWithStringBuilderAppend(Inst *concatCall);
private:
SaveStateBridgesBuilder ssb_ {};
InstVector arrayElements_;
};
} // namespace ark::compiler

View File

@ -223,12 +223,8 @@ IntrinsicInst *SimplifyStringBuilder::CreateConcatIntrinsic(
return concatIntrinsic;
}
bool SimplifyStringBuilder::MatchConcatenation(InstIter &begin, const InstIter &end, ConcatenationMatch &match)
bool CheckUnsupportedCases(Inst *instance)
{
// Walk instruction range [begin, end) and fill the match structure with StringBuilder usage instructions found
auto instance = match.instance;
if (IsUsedOutsideBasicBlock(instance, instance->GetBasicBlock())) {
return false; // Unsupported case: doesn't look like concatenation pattern
}
@ -244,10 +240,21 @@ bool SimplifyStringBuilder::MatchConcatenation(InstIter &begin, const InstIter &
if (appendCount != appendStringCount) {
return false; // Unsupported case: arguments must be strings
}
if (appendCount <= 1 || appendCount > match.appendIntrinsics.size()) {
if (appendCount <= 1 || appendCount > ARGS_NUM_4) {
return false; // Unsupported case: too many strings concatenated
}
return true;
}
bool SimplifyStringBuilder::MatchConcatenation(InstIter &begin, const InstIter &end, ConcatenationMatch &match)
{
auto instance = match.instance;
if (!CheckUnsupportedCases(instance)) {
return false;
}
// Walk instruction range [begin, end) and fill the match structure with StringBuilder usage instructions found
for (; begin != end; ++begin) {
if ((*begin)->IsSaveState()) {
continue;

View File

@ -222,6 +222,33 @@ bool HasUserPhiRecursively(Inst *inst, Marker visited, const FindUserPredicate &
return false;
}
bool HasUserRecursively(Inst *inst, Marker visited, const FindUserPredicate &predicate)
{
// Check if instruction is used in a context defined by predicate
// All Check-instruction users are checked recursively
if (HasUser(inst, predicate)) {
return true;
}
inst->SetMarker(visited);
for (auto &user : inst->GetUsers()) {
auto userInst = user.GetInst();
if (!userInst->IsCheck()) {
continue;
}
if (userInst->IsMarked(visited)) {
continue;
}
if (HasUserRecursively(userInst, visited, predicate)) {
return true;
}
}
return false;
}
size_t CountUsers(Inst *inst, const FindUserPredicate &predicate)
{
size_t count = 0;
@ -347,4 +374,141 @@ bool BreakStringBuilderAppendChains(BasicBlock *block)
return isApplied;
}
Inst *GetStoreArrayIndexConstant(Inst *storeArray)
{
ASSERT(storeArray->GetOpcode() == Opcode::StoreArray);
ASSERT(storeArray->GetInputsCount() > 1);
auto inputInst1 = storeArray->GetDataFlowInput(1U);
if (inputInst1->IsConst()) {
return inputInst1;
}
return nullptr;
}
bool FillArrayElement(Inst *inst, InstVector &arrayElements)
{
if (inst->GetOpcode() == Opcode::StoreArray) {
auto indexInst = GetStoreArrayIndexConstant(inst);
if (indexInst == nullptr) {
return false;
}
ASSERT(indexInst->IsConst());
auto indexValue = indexInst->CastToConstant()->GetIntValue();
if (arrayElements[indexValue] != nullptr) {
return false;
}
auto element = inst->GetDataFlowInput(2U);
arrayElements[indexValue] = element;
}
return true;
}
bool FillArrayElements(Inst *inst, InstVector &arrayElements)
{
for (auto &user : inst->GetUsers()) {
auto userInst = user.GetInst();
if (!FillArrayElement(userInst, arrayElements)) {
return false;
}
if (userInst->GetOpcode() == Opcode::NullCheck) {
if (!FillArrayElements(userInst, arrayElements)) {
return false;
}
}
}
return true;
}
Inst *GetArrayLengthConstant(Inst *newArray)
{
if (newArray->GetOpcode() != Opcode::NewArray) {
return nullptr;
}
ASSERT(newArray->GetInputsCount() > 1);
auto inputInst1 = newArray->GetDataFlowInput(1U);
if (inputInst1->IsConst()) {
return inputInst1;
}
return nullptr;
}
bool CollectArrayElements(Inst *newArray, InstVector &arrayElements)
{
/*
Collect instructions stored to a given array
This functions used to find all the arguments of the calls like:
str.concat(a, b, c)
IR builder generates the following IR for it:
bb_start:
v0 Constant 0x0
v1 Constant 0x1
v2 Constant 0x2
v3 Constant 0x3
bb1:
v9 NewArray class, v3, save_state
v10 StoreArray v9, v0, a
v11 StoreArray v9, v1, b
v12 StoreArray v9, v2, c
v20 CallStatic String::concat str, v9, save_state
Conditions:
- array size is constant (3 in the sample code above)
- every StoreArray instruction stores value by constant index (0, 1 and 2 in the sample code above)
- every element stored only once
- array filled completely
If any of the above is false, this functions returns false and clears array.
If all the above conditions true, this function returns true and fills array.
*/
ASSERT(newArray->GetOpcode() == Opcode::NewArray);
arrayElements.clear();
auto lengthInst = GetArrayLengthConstant(newArray);
if (lengthInst == nullptr) {
return false;
}
ASSERT(lengthInst->IsConst());
auto length = lengthInst->CastToConstant()->GetIntValue();
arrayElements.resize(length);
if (!FillArrayElements(newArray, arrayElements)) {
arrayElements.clear();
return false;
}
// Check if array is filled completely
auto foundNull =
std::find_if(arrayElements.begin(), arrayElements.end(), [](auto &element) { return element == nullptr; });
if (foundNull != arrayElements.end()) {
arrayElements.clear();
return false;
}
return true;
}
void CleanupStoreArrayInstructions(Inst *inst)
{
for (auto &user : inst->GetUsers()) {
auto userInst = user.GetInst();
if (userInst->GetOpcode() == Opcode::StoreArray) {
userInst->ClearFlag(inst_flags::NO_DCE);
}
if (userInst->IsCheck()) {
userInst->ClearFlag(inst_flags::NO_DCE);
CleanupStoreArrayInstructions(userInst);
}
}
}
} // namespace ark::compiler

View File

@ -41,6 +41,7 @@ void ResetInputMarkersRecursively(Inst *inst, Marker visited);
using FindUserPredicate = std::function<bool(User &user)>;
bool HasUser(Inst *inst, const FindUserPredicate &predicate);
bool HasUserPhiRecursively(Inst *inst, Marker visited, const FindUserPredicate &predicate);
bool HasUserRecursively(Inst *inst, Marker visited, const FindUserPredicate &predicate);
size_t CountUsers(Inst *inst, const FindUserPredicate &predicate);
void ResetUserMarkersRecursively(Inst *inst, Marker visited);
Inst *SkipSingleUserCheckInstruction(Inst *inst);
@ -69,6 +70,9 @@ using InputDesc = std::pair<Inst *, unsigned>;
void RemoveFromInstructionInputs(ArenaVector<InputDesc> &inputDescriptors);
bool BreakStringBuilderAppendChains(BasicBlock *block);
Inst *GetArrayLengthConstant(Inst *newArray);
bool CollectArrayElements(Inst *newArray, InstVector &arrayElements);
void CleanupStoreArrayInstructions(Inst *inst);
} // namespace ark::compiler
#endif // COMPILER_OPTIMIZER_OPTIMIZATIONS_STRING_BUILDER_UTILS_H

View File

@ -173,6 +173,7 @@ bool Pipeline::RunOptimizations()
graph->SetUnrollComplete();
}
graph->RunPass<Peepholes>();
graph->RunPass<Cleanup>(false);
graph->RunPass<BranchElimination>();
graph->RunPass<OptimizeStringConcat>();
graph->RunPass<SimplifyStringBuilder>();

View File

@ -42,10 +42,12 @@
//! INST /String::concat/
//! INST_NOT /Intrinsic.StdCoreSbAppendString/
//! INST_NOT /Intrinsic.StdCoreSbToString/
//! INST "StoreArray"
//! PASS_AFTER "OptimizeStringConcat"
//! INST_NOT /String::concat/
//! INST_COUNT /Intrinsic.StdCoreSbAppendString/,2
//! INST_COUNT /Intrinsic.StdCoreSbToString/,1
//! INST_NOT "StoreArray"
//! PASS_BEFORE "Escape"
//! INST_COUNT "NewArray", 1
//! PASS_AFTER "Escape"
@ -56,10 +58,12 @@
//! INST /String::concat/
//! INST_NOT /Intrinsic.StdCoreSbAppendString/
//! INST_NOT /Intrinsic.StdCoreSbToString/
//! INST "StoreArray"
//! PASS_AFTER "OptimizeStringConcat"
//! INST_NOT /String::concat/
//! INST_COUNT /Intrinsic.StdCoreSbAppendString/,3
//! INST_COUNT /Intrinsic.StdCoreSbToString/,1
//! INST_NOT "StoreArray"
//! PASS_BEFORE "Escape"
//! INST_COUNT "NewArray", 1
//! PASS_AFTER "Escape"
@ -70,10 +74,12 @@
//! INST /String::concat/
//! INST_NOT /Intrinsic.StdCoreSbAppendString/
//! INST_NOT /Intrinsic.StdCoreSbToString/
//! INST "StoreArray"
//! PASS_AFTER "OptimizeStringConcat"
//! INST_NOT /String::concat/
//! INST_COUNT /Intrinsic.StdCoreSbAppendString/,4
//! INST_COUNT /Intrinsic.StdCoreSbToString/,1
//! INST_NOT "StoreArray"
//! PASS_BEFORE "Escape"
//! INST_COUNT "NewArray", 1
//! PASS_AFTER "Escape"
@ -84,10 +90,12 @@
//! INST /String::concat/
//! INST_NOT /Intrinsic.StdCoreSbAppendString/
//! INST_NOT /Intrinsic.StdCoreSbToString/
//! INST "StoreArray"
//! PASS_AFTER "OptimizeStringConcat"
//! INST_NOT /String::concat/
//! INST_COUNT /Intrinsic.StdCoreSbAppendString/,5
//! INST_COUNT /Intrinsic.StdCoreSbToString/,1
//! INST_NOT "StoreArray"
//! PASS_BEFORE "Escape"
//! INST_COUNT "NewArray", 2
//! PASS_AFTER "Escape"
@ -98,10 +106,12 @@
//! INST /String::concat/
//! INST_NOT /Intrinsic.StdCoreSbAppendString/
//! INST_NOT /Intrinsic.StdCoreSbToString/
//! INST "StoreArray"
//! PASS_AFTER "OptimizeStringConcat"
//! INST_NOT /String::concat/
//! INST_COUNT /Intrinsic.StdCoreSbAppendString/,6
//! INST_COUNT /Intrinsic.StdCoreSbToString/,1
//! INST_NOT "StoreArray"
//! PASS_BEFORE "Escape"
//! INST_COUNT "NewArray", 2
//! PASS_AFTER "Escape"
@ -112,10 +122,12 @@
//! INST /String::concat/
//! INST_NOT /Intrinsic.StdCoreSbAppendString/
//! INST_NOT /Intrinsic.StdCoreSbToString/
//! INST "StoreArray"
//! PASS_AFTER "OptimizeStringConcat"
//! INST_NOT /String::concat/
//! INST_COUNT /Intrinsic.StdCoreSbAppendString/,4
//! INST_COUNT /Intrinsic.StdCoreSbToString/,1
//! INST_NOT "StoreArray"
//! PASS_BEFORE "Escape"
//! INST_COUNT "NewArray", 1
//! PASS_AFTER "Escape"
@ -126,10 +138,12 @@
//! INST /String::concat/
//! INST_NOT /Intrinsic.StdCoreSbAppendString/
//! INST_NOT /Intrinsic.StdCoreSbToString/
//! INST "StoreArray"
//! PASS_AFTER "OptimizeStringConcat"
//! INST_NOT /String::concat/
//! INST_COUNT /Intrinsic.StdCoreSbAppendString/,6
//! INST_COUNT /Intrinsic.StdCoreSbToString/,1
//! INST_NOT "StoreArray"
//! PASS_BEFORE "Escape"
//! INST_COUNT "NewArray", 2
//! PASS_AFTER "Escape"