• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "optimizer/analysis/reg_alloc_verifier.h"
17 #include "optimizer/analysis/liveness_analyzer.h"
18 #include "optimizer/analysis/live_registers.h"
19 #include "optimizer/ir/basicblock.h"
20 #include "optimizer/code_generator/callconv.h"
21 #include "optimizer/code_generator/codegen.h"
22 #include "optimizer/optimizations/regalloc/reg_type.h"
23 
24 namespace ark::compiler {
25 namespace {
ToString(LocationState::State state)26 std::string ToString(LocationState::State state)
27 {
28     switch (state) {
29         case LocationState::State::UNKNOWN:
30             return "UNKNOWN";
31         case LocationState::State::KNOWN:
32             return "KNOWN";
33         case LocationState::State::CONFLICT:
34             return "CONFLICT";
35         default:
36             UNREACHABLE();
37     }
38 }
39 
GetPhiLocationState(const BlockState & state,const ArenaVector<LocationState> & immediates,const LifeIntervals * interval,bool isHigh)40 const LocationState &GetPhiLocationState(const BlockState &state, const ArenaVector<LocationState> &immediates,
41                                          const LifeIntervals *interval, bool isHigh)
42 {
43     auto location = interval->GetLocation();
44     if (location.IsStack()) {
45         ASSERT(!isHigh);
46         return state.GetStack(location.GetValue());
47     }
48     if (location.IsConstant()) {
49         ASSERT(location.GetValue() < immediates.size());
50         return immediates[location.GetValue()];
51     }
52     if (location.IsFpRegister()) {
53         ASSERT(IsFloatType(interval->GetType()));
54         return state.GetVReg(location.GetValue() + (isHigh ? 1U : 0U));
55     }
56     ASSERT(location.IsRegister());
57     return state.GetReg(location.GetValue() + (isHigh ? 1U : 0U));
58 }
59 
GetPhiLocationState(BlockState * state,const LifeIntervals * interval,bool isHigh)60 LocationState &GetPhiLocationState(BlockState *state, const LifeIntervals *interval, bool isHigh)
61 {
62     auto location = interval->GetLocation();
63     if (location.IsStack()) {
64         ASSERT(!isHigh);
65         return state->GetStack(location.GetValue());
66     }
67     if (location.IsFpRegister()) {
68         ASSERT(IsFloatType(interval->GetType()));
69         return state->GetVReg(location.GetValue() + (isHigh ? 1U : 0U));
70     }
71     ASSERT(location.IsRegister());
72     return state->GetReg(location.GetValue() + (isHigh ? 1U : 0U));
73 }
74 
MergeImpl(const ArenaVector<LocationState> & from,ArenaVector<LocationState> * to)75 bool MergeImpl(const ArenaVector<LocationState> &from, ArenaVector<LocationState> *to)
76 {
77     bool updated = false;
78     for (size_t offset = 0; offset < from.size(); ++offset) {
79         if (to->at(offset).ShouldSkip()) {
80             to->at(offset).SetSkip(false);
81             continue;
82         }
83         updated |= to->at(offset).Merge(from[offset]);
84     }
85     return updated;
86 }
87 
88 class BlockStates {
89 public:
BlockStates(size_t regs,size_t vregs,size_t stackSlots,size_t stackParams,ArenaAllocator * allocator)90     BlockStates(size_t regs, size_t vregs, size_t stackSlots, size_t stackParams, ArenaAllocator *allocator)
91         : startState_(regs, vregs, stackSlots, stackParams, allocator),
92           endState_(regs, vregs, stackSlots, stackParams, allocator)
93     {
94     }
95     ~BlockStates() = default;
96     NO_COPY_SEMANTIC(BlockStates);
97     NO_MOVE_SEMANTIC(BlockStates);
98 
GetStart()99     BlockState &GetStart()
100     {
101         return startState_;
102     }
103 
GetEnd()104     BlockState &GetEnd()
105     {
106         return endState_;
107     }
108 
ResetEndToStart()109     BlockState &ResetEndToStart()
110     {
111         endState_.Copy(&startState_);
112         return endState_;
113     }
114 
IsUpdated() const115     bool IsUpdated() const
116     {
117         return updated_;
118     }
119 
SetUpdated(bool upd)120     void SetUpdated(bool upd)
121     {
122         updated_ = upd;
123     }
124 
IsVisited() const125     bool IsVisited() const
126     {
127         return visited_;
128     }
129 
SetVisited(bool visited)130     void SetVisited(bool visited)
131     {
132         visited_ = visited;
133     }
134 
135 private:
136     BlockState startState_;
137     BlockState endState_;
138     bool updated_ {false};
139     bool visited_ {false};
140 };
141 
InitStates(ArenaUnorderedMap<uint32_t,BlockStates> * blocks,const Graph * graph)142 void InitStates(ArenaUnorderedMap<uint32_t, BlockStates> *blocks, const Graph *graph)
143 {
144     auto usedRegs = graph->GetUsedRegs<DataType::INT64>()->size();
145     auto usedVregs = graph->GetUsedRegs<DataType::FLOAT64>()->size();
146     for (auto &bb : graph->GetVectorBlocks()) {
147         if (bb == nullptr) {
148             continue;
149         }
150         [[maybe_unused]] auto res = blocks->try_emplace(bb->GetId(), usedRegs, usedVregs, GetMaxNumStackSlots(),
151                                                         GetMaxNumStackSlots(), graph->GetLocalAllocator());
152         ASSERT(res.second);
153     }
154 }
155 
CheckAllBlocksVisited(const ArenaUnorderedMap<uint32_t,BlockStates> & blocks)156 void CheckAllBlocksVisited([[maybe_unused]] const ArenaUnorderedMap<uint32_t, BlockStates> &blocks)
157 {
158 #ifndef NDEBUG
159     for (auto &blockState : blocks) {
160         ASSERT(blockState.second.IsVisited());
161     }
162 #endif
163 }
164 
IsRegisterPair(Location location,DataType::Type type,Graph * graph)165 bool IsRegisterPair(Location location, DataType::Type type, Graph *graph)
166 {
167     if (!location.IsRegister()) {
168         return false;
169     }
170     return Is64Bits(type, graph->GetArch()) && !Is64BitsArch(graph->GetArch());
171 }
172 
IsRegisterPair(const LifeIntervals * li)173 bool IsRegisterPair(const LifeIntervals *li)
174 {
175     if (!li->HasReg()) {
176         return false;
177     }
178     return IsRegisterPair(Location::MakeRegister(li->GetReg()), li->GetType(),
179                           li->GetInst()->GetBasicBlock()->GetGraph());
180 }
181 }  // namespace
182 
Merge(const LocationState & other)183 bool LocationState::Merge(const LocationState &other)
184 {
185     if (state_ == LocationState::State::CONFLICT) {
186         return false;
187     }
188     if (state_ == LocationState::State::UNKNOWN) {
189         state_ = other.state_;
190         id_ = other.id_;
191         return other.state_ != LocationState::State::UNKNOWN;
192     }
193     if (other.state_ == LocationState::State::CONFLICT) {
194         state_ = LocationState::State::CONFLICT;
195         return true;
196     }
197     if (other.state_ == LocationState::State::KNOWN && state_ == LocationState::State::KNOWN && other.id_ != id_) {
198         state_ = LocationState::State::CONFLICT;
199         return true;
200     }
201     return false;
202 }
203 
BlockState(size_t regs,size_t vregs,size_t stackSlots,size_t stackParams,ArenaAllocator * alloc)204 BlockState::BlockState(size_t regs, size_t vregs, size_t stackSlots, size_t stackParams, ArenaAllocator *alloc)
205     : regs_(regs, alloc->Adapter()),
206       vregs_(vregs, alloc->Adapter()),
207       stack_(stackSlots, alloc->Adapter()),
208       stackParam_(stackParams, alloc->Adapter()),
209       stackArg_(0, alloc->Adapter())
210 
211 {
212 }
213 
Merge(const BlockState & state,const PhiInstSafeIter & phis,BasicBlock * pred,const ArenaVector<LocationState> & immediates,const LivenessAnalyzer & la)214 bool BlockState::Merge(const BlockState &state, const PhiInstSafeIter &phis, BasicBlock *pred,
215                        const ArenaVector<LocationState> &immediates, const LivenessAnalyzer &la)
216 {
217     bool updated = false;
218     /* Phi instructions are resolved into moves at the end of predecessor blocks,
219      * but corresponding locations contain ids of instructions merged by a phi.
220      * Phi's location at the beginning of current block is only updated when
221      * the same location at the end of predecessor holds result of an instruction
222      * that is a phi's input. Otherwise phi's location state will be either remains unknown,
223      * or it will be merged to conflicting state.
224      */
225     constexpr std::array<bool, 2U> IS_HIGH = {false, true};
226     for (auto phi : phis) {
227         auto phiInterval = la.GetInstLifeIntervals(phi);
228         auto input = phi->CastToPhi()->GetPhiDataflowInput(pred);
229         for (size_t isHighIdx = 0; isHighIdx < (IsRegisterPair(phiInterval) ? 2U : 1U); isHighIdx++) {
230             auto &inputState = GetPhiLocationState(state, immediates, phiInterval, IS_HIGH[isHighIdx]);
231             auto &phiState = GetPhiLocationState(this, phiInterval, IS_HIGH[isHighIdx]);
232 
233             if (inputState.GetState() != LocationState::State::KNOWN) {
234                 continue;
235             }
236             if (inputState.IsValid(input)) {
237                 updated = phiState.GetState() != LocationState::State::KNOWN || phiState.GetId() != phi->GetId();
238                 phiState.SetId(phi->GetId());
239                 // don't merge it
240                 phiState.SetSkip(true);
241             }
242         }
243     }
244     updated |= MergeImpl(state.regs_, &regs_);
245     updated |= MergeImpl(state.vregs_, &vregs_);
246     updated |= MergeImpl(state.stack_, &stack_);
247     updated |= MergeImpl(state.stackParam_, &stackParam_);
248     // note that stack_arg_ is not merged as it is only used during call handing
249     return updated;
250 }
251 
Copy(BlockState * state)252 void BlockState::Copy(BlockState *state)
253 {
254     std::copy(state->regs_.begin(), state->regs_.end(), regs_.begin());
255     std::copy(state->vregs_.begin(), state->vregs_.end(), vregs_.begin());
256     std::copy(state->stack_.begin(), state->stack_.end(), stack_.begin());
257     std::copy(state->stackParam_.begin(), state->stackParam_.end(), stackParam_.begin());
258     // note that stack_arg_ is not merged as it is only used during call handing
259 }
260 
RegAllocVerifier(Graph * graph,bool saveLiveRegsOnCall)261 RegAllocVerifier::RegAllocVerifier(Graph *graph, bool saveLiveRegsOnCall)
262     : Analysis(graph),
263       immediates_(graph->GetLocalAllocator()->Adapter()),
264       savedRegs_(GetGraph()->GetLocalAllocator()->Adapter()),
265       savedVregs_(GetGraph()->GetLocalAllocator()->Adapter()),
266       saveLiveRegs_(saveLiveRegsOnCall)
267 {
268 }
269 
InitImmediates()270 void RegAllocVerifier::InitImmediates()
271 {
272     immediates_.clear();
273     for (size_t immSlot = 0; immSlot < GetGraph()->GetSpilledConstantsCount(); ++immSlot) {
274         auto con = GetGraph()->GetSpilledConstant(immSlot);
275         immediates_.emplace_back(LocationState::State::KNOWN, con->GetId());
276     }
277 }
278 
GetLocationState(Location location)279 LocationState &RegAllocVerifier::GetLocationState(Location location)
280 {
281     auto loc = location.GetKind();
282     auto offset = location.GetValue();
283 
284     if (loc == LocationType::STACK) {
285         return currentState_->GetStack(offset);
286     }
287     if (loc == LocationType::REGISTER) {
288         return currentState_->GetReg(offset);
289     }
290     if (loc == LocationType::FP_REGISTER) {
291         return currentState_->GetVReg(offset);
292     }
293     if (loc == LocationType::STACK_ARGUMENT) {
294         return currentState_->GetStackArg(offset);
295     }
296     if (loc == LocationType::STACK_PARAMETER) {
297         return currentState_->GetStackParam(offset);
298     }
299     ASSERT(loc == LocationType::IMMEDIATE);
300     ASSERT(offset < immediates_.size());
301     return immediates_[offset];
302 }
303 
304 // Apply callback to a location corresponding to loc, offset and type.
305 // If location is represented by registers pair then apply the callback to both parts.
306 // Return true if all invocations of the callback returned true.
307 template <typename T>
ForEachLocation(Location location,DataType::Type type,T callback)308 bool RegAllocVerifier::ForEachLocation(Location location, DataType::Type type, T callback)
309 {
310     bool success = callback(GetLocationState(location));
311     if (IsRegisterPair(location, type, GetGraph())) {
312         auto piredReg = Location::MakeRegister(location.GetValue() + 1);
313         success &= callback(GetLocationState(piredReg));
314     }
315     return success;
316 }
317 
UpdateLocation(Location location,DataType::Type type,uint32_t instId)318 void RegAllocVerifier::UpdateLocation(Location location, DataType::Type type, uint32_t instId)
319 {
320     ForEachLocation(location, type, [instId](auto &state) {
321         state.SetId(instId);
322         return true;
323     });
324 }
325 
HandleDest(Inst * inst)326 void RegAllocVerifier::HandleDest(Inst *inst)
327 {
328     if (inst->NoDest()) {
329         return;
330     }
331     auto type = inst->GetType();
332     if (GetGraph()->GetZeroReg() != GetInvalidReg() && inst->GetDstReg() == GetGraph()->GetZeroReg()) {
333         UpdateLocation(Location::MakeRegister(inst->GetDstReg()), type, LocationState::ZERO_INST);
334         return;
335     }
336 
337     if (inst->GetDstCount() == 1) {
338         UpdateLocation(Location::MakeRegister(inst->GetDstReg(), type), type, inst->GetId());
339         return;
340     }
341 
342     [[maybe_unused]] size_t handledUsers = 0;
343     for (auto &user : inst->GetUsers()) {
344         if (IsPseudoUserOfMultiOutput(user.GetInst())) {
345             auto instId = user.GetInst()->GetId();
346             auto idx = user.GetInst()->CastToLoadPairPart()->GetSrcRegIndex();
347             UpdateLocation(Location::MakeRegister(inst->GetDstReg(idx), type), type, instId);
348             ++handledUsers;
349         }
350     }
351     ASSERT(handledUsers == inst->GetDstCount());
352 }
353 
PropagateBlockState(BasicBlock * currentBlock,BlockState * currentState,const ArenaVector<LocationState> & immediates,ArenaUnorderedMap<uint32_t,BlockStates> * blocks)354 BasicBlock *PropagateBlockState(BasicBlock *currentBlock, BlockState *currentState,
355                                 const ArenaVector<LocationState> &immediates,
356                                 ArenaUnorderedMap<uint32_t, BlockStates> *blocks)
357 {
358     BasicBlock *nextBlock {nullptr};
359     auto &la = currentBlock->GetGraph()->GetAnalysis<LivenessAnalyzer>();
360     for (auto succ : currentBlock->GetSuccsBlocks()) {
361         auto phis = succ->PhiInstsSafe();
362         auto &succState = blocks->at(succ->GetId());
363         bool mergeUpdated = succState.GetStart().Merge(*currentState, phis, currentBlock, immediates, la);
364         // if merged did not update the state, but successor is not visited yet then force its visit
365         mergeUpdated |= !succState.IsVisited();
366         succState.SetUpdated(succState.IsUpdated() || mergeUpdated);
367         if (mergeUpdated) {
368             nextBlock = succ;
369         }
370     }
371     return nextBlock;
372 }
373 
RunImpl()374 bool RegAllocVerifier::RunImpl()
375 {
376     ArenaUnorderedMap<uint32_t, BlockStates> blocks(GetGraph()->GetLocalAllocator()->Adapter());
377     InitStates(&blocks, GetGraph());
378     InitImmediates();
379     implicitNullCheckHandledMarker_ = GetGraph()->NewMarker();
380 
381     success_ = true;
382     currentBlock_ = GetGraph()->GetStartBlock();
383     while (success_) {
384         ASSERT(currentBlock_ != nullptr);
385 
386         blocks.at(currentBlock_->GetId()).SetUpdated(false);
387         blocks.at(currentBlock_->GetId()).SetVisited(true);
388         // use state at the end of the block as current state and reset it to the state
389         // at the beginning of the block before processing.
390         currentState_ = &blocks.at(currentBlock_->GetId()).ResetEndToStart();
391 
392         ProcessCurrentBlock();
393         if (!success_) {
394             break;
395         }
396 
397         currentBlock_ = PropagateBlockState(currentBlock_, currentState_, immediates_, &blocks);
398         if (currentBlock_ != nullptr) {
399             continue;
400         }
401         // pick a block pending processing
402         auto it = std::find_if(blocks.begin(), blocks.end(), [](auto &t) { return t.second.IsUpdated(); });
403         if (it == blocks.end()) {
404             break;
405         }
406         const auto &bbs = GetGraph()->GetVectorBlocks();
407         auto bbId = it->first;
408         auto blockIt =
409             std::find_if(bbs.begin(), bbs.end(), [bbId](auto bb) { return bb != nullptr && bb->GetId() == bbId; });
410         ASSERT(blockIt != bbs.end());
411         currentBlock_ = *blockIt;
412     }
413 
414     GetGraph()->EraseMarker(implicitNullCheckHandledMarker_);
415     if (success_) {
416         CheckAllBlocksVisited(blocks);
417     }
418     return success_;
419 }
420 
ProcessCurrentBlock()421 void RegAllocVerifier::ProcessCurrentBlock()
422 {
423     for (auto inst : currentBlock_->InstsSafe()) {
424         if (!success_) {
425             return;
426         }
427 #ifdef PANDA_WITH_IRTOC
428         if (IsSaveRestoreRegisters(inst)) {
429             HandleSaveRestoreRegisters(inst);
430             continue;
431         }
432 #endif
433         if (inst->GetOpcode() == Opcode::ReturnInlined) {
434             // ReturnInlined is pseudo instruction having SaveState input that
435             // only prolongs SaveState input's lifetime. There are no guarantees that
436             // SaveState's inputs will be stored in locations specified in SaveState
437             // at ReturnInlined.
438             continue;
439         }
440 
441         TryHandleImplicitNullCheck(inst);
442         // pseudo user of multi output will be handled by HandleDest
443         if (inst->IsSaveState() || IsPseudoUserOfMultiOutput(inst)) {
444             continue;
445         }
446 
447         if (inst->IsCall() && static_cast<CallInst *>(inst)->IsInlined()) {
448             ASSERT(inst->GetDstReg() == GetInvalidReg());
449             continue;
450         }
451 
452         if (inst->IsParameter()) {
453             HandleParameter(inst->CastToParameter());
454         } else if (inst->IsSpillFill()) {
455             HandleSpillFill(inst->CastToSpillFill());
456         } else if (inst->IsConst()) {
457             HandleConst(inst->CastToConstant());
458         } else {
459             HandleInst(inst);
460         }
461     }
462 }
463 
464 // Set inst's id to corresponding location
HandleParameter(ParameterInst * inst)465 void RegAllocVerifier::HandleParameter(ParameterInst *inst)
466 {
467     auto sf = inst->GetLocationData();
468     UpdateLocation(sf.GetDst(), inst->GetType(), inst->GetId());
469 }
470 
SameState(LocationState & left,LocationState & right)471 bool SameState(LocationState &left, LocationState &right)
472 {
473     return left.GetId() == right.GetId() && left.GetState() == right.GetState();
474 }
475 
476 // Copy inst's id from source location to destination location,
477 // source location should contain known value.
HandleSpillFill(SpillFillInst * inst)478 void RegAllocVerifier::HandleSpillFill(SpillFillInst *inst)
479 {
480     for (auto sf : inst->GetSpillFills()) {
481         LocationState *state = nullptr;
482         success_ &= ForEachLocation(
483             sf.GetSrc(), sf.GetType(), [&state, &sf, inst, arch = GetGraph()->GetArch()](LocationState &st) {
484                 if (state == nullptr) {
485                     state = &st;
486                 } else if (!SameState(*state, st)) {
487                     COMPILER_LOG(ERROR, REGALLOC) << "SpillFill is accessing " << sf.GetSrc().ToString(arch)
488                                                   << " with different state for high and low parts";
489                     return false;
490                 }
491                 if (st.GetState() == LocationState::State::KNOWN) {
492                     return true;
493                 }
494                 COMPILER_LOG(ERROR, REGALLOC)
495                     << "SpillFill is copying value from location with state " << ToString(st.GetState()) << ", "
496                     << inst->GetId() << " read from " << sf.GetSrc().ToString(arch);
497                 return false;
498             });
499         ASSERT(state != nullptr);
500         UpdateLocation(sf.GetDst(), sf.GetType(), state->GetId());
501     }
502 }
503 
504 // Set instn's id to corresponding location.
HandleConst(ConstantInst * inst)505 void RegAllocVerifier::HandleConst(ConstantInst *inst)
506 {
507     if (inst->GetDstReg() != GetInvalidReg()) {
508         HandleDest(inst);
509         return;
510     }
511 
512     // if const inst does not have valid register then it was spilled to imm table.
513     auto immSlot = GetGraph()->FindSpilledConstantSlot(inst->CastToConstant());
514     // zero const is a special case - we're using zero reg to encode it.
515     if (immSlot == GetInvalidImmTableSlot() && IsZeroConstantOrNullPtr(inst)) {
516         return;
517     }
518 
519     // if there is no place in the imm table, constant will be spilled to the stack.
520     ASSERT(immSlot != GetInvalidImmTableSlot() || !GetGraph()->HasAvailableConstantSpillSlots());
521 }
522 
523 // Verify instn's inputs and set instn's id to destination location.
524 // CC-OFFNXT(huge_depth[C++]) solid logic
HandleInst(Inst * inst)525 void RegAllocVerifier::HandleInst(Inst *inst)
526 {
527     if (!InstHasPseudoInputs(inst)) {
528         for (size_t i = 0; i < inst->GetInputsCount(); i++) {
529             auto input = inst->GetDataFlowInput(i);
530             if (input->NoDest() && !IsPseudoUserOfMultiOutput(input)) {
531                 ASSERT(!inst->GetLocation(i).IsFixedRegister());
532                 continue;
533             }
534 
535             auto inputType = inst->GetInputType(i);
536             if (inputType == DataType::NO_TYPE) {
537                 ASSERT(inst->GetOpcode() == Opcode::CallIndirect);
538                 inputType = Is64BitsArch(GetGraph()->GetArch()) ? DataType::INT64 : DataType::INT32;
539             } else {
540                 inputType = ConvertRegType(GetGraph(), inputType);
541             }
542 
543             success_ &= ForEachLocation(inst->GetLocation(i), inputType, [input, inst, i](LocationState &location) {
544                 if (location.GetState() != LocationState::State::KNOWN) {
545                     COMPILER_LOG(ERROR, REGALLOC) << "Input #" << i << " is loaded from location with state "
546                                                   << ToString(location.GetState()) << std::endl
547                                                   << "Affected inst: " << *inst << std::endl
548                                                   << "Input inst: " << *input;
549                     return false;
550                 }
551                 if (location.IsValid(input)) {
552                     return true;
553                 }
554                 COMPILER_LOG(ERROR, REGALLOC) << "Input #" << i << " is loaded from location holding instruction "
555                                               << location.GetId() << " instead of " << input->GetId() << std::endl
556                                               << "Affected inst: " << *inst;
557                 return false;
558             });
559         }
560     }
561     HandleDest(inst);
562 }
563 
564 #ifdef PANDA_WITH_IRTOC
IsSaveRestoreRegisters(Inst * inst)565 bool RegAllocVerifier::IsSaveRestoreRegisters(Inst *inst)
566 {
567     if (!inst->IsIntrinsic()) {
568         return false;
569     }
570     auto intrinsicId = inst->CastToIntrinsic()->GetIntrinsicId();
571     return intrinsicId == RuntimeInterface::IntrinsicId::INTRINSIC_SAVE_REGISTERS_EP ||
572            intrinsicId == RuntimeInterface::IntrinsicId::INTRINSIC_RESTORE_REGISTERS_EP;
573 }
574 
HandleSaveRestoreRegisters(Inst * inst)575 void RegAllocVerifier::HandleSaveRestoreRegisters(Inst *inst)
576 {
577     ASSERT(inst->IsIntrinsic());
578     auto usedRegs = GetGraph()->GetUsedRegs<DataType::INT64>()->size();
579     switch (inst->CastToIntrinsic()->GetIntrinsicId()) {
580         case RuntimeInterface::IntrinsicId::INTRINSIC_SAVE_REGISTERS_EP:
581             ASSERT(savedRegs_.empty());
582             for (size_t reg = 0; reg < usedRegs; reg++) {
583                 savedRegs_.push_back(currentState_->GetReg(reg));
584             }
585             break;
586         case RuntimeInterface::IntrinsicId::INTRINSIC_RESTORE_REGISTERS_EP:
587             ASSERT(!savedRegs_.empty());
588             for (size_t reg = 0; reg < usedRegs; reg++) {
589                 if (savedRegs_[reg].GetState() == LocationState::State::UNKNOWN) {
590                     continue;
591                 }
592                 currentState_->GetReg(reg) = savedRegs_[reg];
593             }
594             savedRegs_.clear();
595             break;
596         default:
597             UNREACHABLE();
598     }
599 
600     HandleDest(inst);
601 }
602 #endif
603 
604 // Implicit null checks are not encoded as machine instructions, but instead
605 // added to method's metadata that allow to treat some memory-access related
606 // signals as null pointer exceptions.
607 // SaveState instruction bound to implicit null check captures locations
608 // of its inputs at first null check's user (See RegAllocResolver::GetExplicitUser).
609 // Check if current instruction use implicit null check that was not yet handled
610 // and handle its save state.
TryHandleImplicitNullCheck(Inst * inst)611 void RegAllocVerifier::TryHandleImplicitNullCheck(Inst *inst)
612 {
613     NullCheckInst *nc = nullptr;
614     for (auto &input : inst->GetInputs()) {
615         if (input.GetInst()->IsNullCheck() && input.GetInst()->CastToNullCheck()->IsImplicit() &&
616             !input.GetInst()->IsMarked(implicitNullCheckHandledMarker_)) {
617             nc = input.GetInst()->CastToNullCheck();
618             break;
619         }
620     }
621     if (nc == nullptr) {
622         return;
623     }
624     nc->SetMarker(implicitNullCheckHandledMarker_);
625 }
626 
627 }  // namespace ark::compiler
628