diff options
Diffstat (limited to 'src/compiler/dex/compiler_utility.cc')
-rw-r--r-- | src/compiler/dex/compiler_utility.cc | 799 |
1 files changed, 799 insertions, 0 deletions
diff --git a/src/compiler/dex/compiler_utility.cc b/src/compiler/dex/compiler_utility.cc new file mode 100644 index 0000000000..b5185b00e6 --- /dev/null +++ b/src/compiler/dex/compiler_utility.cc @@ -0,0 +1,799 @@ +/* + * Copyright (C) 2011 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. + */ + +#include "compiler_internals.h" + +namespace art { + +const char* extended_mir_op_names[kMirOpLast - kMirOpFirst] = { + "Phi", + "Copy", + "FusedCmplFloat", + "FusedCmpgFloat", + "FusedCmplDouble", + "FusedCmpgDouble", + "FusedCmpLong", + "Nop", + "OpNullCheck", + "OpRangeCheck", + "OpDivZeroCheck", + "Check1", + "Check2", + "Select", +}; + +#ifdef WITH_MEMSTATS +struct Memstats { + uint32_t alloc_stats[kNumAllocKinds]; + int list_sizes[kNumListKinds]; + int list_wasted[kNumListKinds]; + int list_grows[kNumListKinds]; + int list_max_elems[kNumListKinds]; + int bit_map_sizes[kNumBitMapKinds]; + int bit_map_wasted[kNumBitMapKinds]; + int bit_map_grows[kNumBitMapKinds]; +}; + +const char* alloc_names[kNumAllocKinds] = { + "Misc ", + "BasicBlock ", + "LIR ", + "MIR ", + "DataFlow ", + "GrowList ", + "GrowBitMap ", + "Dalvik2SSA ", + "DebugInfo ", + "Successor ", + "RegAlloc ", + "Data ", + "Preds ", +}; + +const char* list_names[kNumListKinds] = { + "Misc ", + "block_list ", + "SSAtoDalvik ", + "dfs_order ", + "dfs_post_order ", + "dom_post_order_traversal ", + "throw_launch_pads ", + "suspend_launch_pads ", + "switch_tables ", + "fill_array_data ", + "SuccessorBlocks ", + "Predecessors ", +}; + +const char* bit_map_names[kNumBitMapKinds] = { + "Misc ", + "Use ", + "Def ", + "LiveIn ", + "BlockMatrix ", + "Dominators ", + "IDominated ", + "DomFrontier ", + "Phi ", + "TmpBlocks ", + "InputBlocks ", + "RegisterV ", + "TempSSARegisterV ", + "Null Check ", + "TmpBlockV ", + "Predecessors ", +}; +#endif + +#define kArenaBitVectorGrowth 4 /* increase by 4 uint32_ts when limit hit */ + +/* Allocate the initial memory block for arena-based allocation */ +bool HeapInit(CompilationUnit* cu) +{ + DCHECK(cu->arena_head == NULL); + cu->arena_head = + static_cast<ArenaMemBlock*>(malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE)); + if (cu->arena_head == NULL) { + LOG(FATAL) << "No memory left to create compiler heap memory"; + } + cu->arena_head->block_size = ARENA_DEFAULT_SIZE; + cu->current_arena = cu->arena_head; + cu->current_arena->bytes_allocated = 0; + cu->current_arena->next = NULL; + cu->num_arena_blocks = 1; +#ifdef WITH_MEMSTATS + cu->mstats = (Memstats*) NewMem(cu, sizeof(Memstats), true, + kAllocDebugInfo); +#endif + return true; +} + +/* Arena-based malloc for compilation tasks */ +void* NewMem(CompilationUnit* cu, size_t size, bool zero, oat_alloc_kind kind) +{ + size = (size + 3) & ~3; +#ifdef WITH_MEMSTATS + if (cu->mstats != NULL) { + cu->mstats->alloc_stats[kind] += size; + } +#endif +retry: + /* Normal case - space is available in the current page */ + if (size + cu->current_arena->bytes_allocated <= + cu->current_arena->block_size) { + void *ptr; + ptr = &cu->current_arena->ptr[cu->current_arena->bytes_allocated]; + cu->current_arena->bytes_allocated += size; + if (zero) { + memset(ptr, 0, size); + } + return ptr; + } else { + /* + * See if there are previously allocated arena blocks before the last + * reset + */ + if (cu->current_arena->next) { + cu->current_arena = cu->current_arena->next; + cu->current_arena->bytes_allocated = 0; + goto retry; + } + + size_t block_size = (size < ARENA_DEFAULT_SIZE) ? ARENA_DEFAULT_SIZE : size; + /* Time to allocate a new arena */ + ArenaMemBlock *new_arena = + static_cast<ArenaMemBlock*>(malloc(sizeof(ArenaMemBlock) + block_size)); + if (new_arena == NULL) { + LOG(FATAL) << "Arena allocation failure"; + } + new_arena->block_size = block_size; + new_arena->bytes_allocated = 0; + new_arena->next = NULL; + cu->current_arena->next = new_arena; + cu->current_arena = new_arena; + cu->num_arena_blocks++; + if (cu->num_arena_blocks > 20000) { + LOG(INFO) << "Total arena pages: " << cu->num_arena_blocks; + } + goto retry; + } +} + +/* Reclaim all the arena blocks allocated so far */ +void ArenaReset(CompilationUnit* cu) +{ + ArenaMemBlock* head = cu->arena_head; + while (head != NULL) { + ArenaMemBlock* p = head; + head = head->next; + free(p); + } + cu->arena_head = NULL; + cu->current_arena = NULL; +} + +/* Growable List initialization */ +void CompilerInitGrowableList(CompilationUnit* cu, GrowableList* g_list, + size_t init_length, oat_list_kind kind) +{ + g_list->num_allocated = init_length; + g_list->num_used = 0; + g_list->elem_list = static_cast<uintptr_t *>(NewMem(cu, sizeof(intptr_t) * init_length, + true, kAllocGrowableList)); +#ifdef WITH_MEMSTATS + cu->mstats->list_sizes[kind] += sizeof(uintptr_t) * init_length; + g_list->kind = kind; + if (static_cast<int>(init_length) > cu->mstats->list_max_elems[kind]) { + cu->mstats->list_max_elems[kind] = init_length; + } +#endif +} + +/* Expand the capacity of a growable list */ +static void ExpandGrowableList(CompilationUnit* cu, GrowableList* g_list) +{ + int new_length = g_list->num_allocated; + if (new_length < 128) { + new_length <<= 1; + } else { + new_length += 128; + } + uintptr_t *new_array = + static_cast<uintptr_t*>(NewMem(cu, sizeof(uintptr_t) * new_length, true, + kAllocGrowableList)); + memcpy(new_array, g_list->elem_list, sizeof(uintptr_t) * g_list->num_allocated); +#ifdef WITH_MEMSTATS + cu->mstats->list_sizes[g_list->kind] += sizeof(uintptr_t) * new_length; + cu->mstats->list_wasted[g_list->kind] += + sizeof(uintptr_t) * g_list->num_allocated; + cu->mstats->list_grows[g_list->kind]++; + if (new_length > cu->mstats->list_max_elems[g_list->kind]) { + cu->mstats->list_max_elems[g_list->kind] = new_length; + } +#endif + g_list->num_allocated = new_length; + g_list->elem_list = new_array; +} + +/* Insert a new element into the growable list */ +void InsertGrowableList(CompilationUnit* cu, GrowableList* g_list, + uintptr_t elem) +{ + DCHECK_NE(g_list->num_allocated, 0U); + if (g_list->num_used == g_list->num_allocated) { + ExpandGrowableList(cu, g_list); + } + g_list->elem_list[g_list->num_used++] = elem; +} + +/* Delete an element from a growable list. Element must be present */ +void DeleteGrowableList(GrowableList* g_list, uintptr_t elem) +{ + bool found = false; + for (unsigned int i = 0; i < g_list->num_used; i++) { + if (!found && g_list->elem_list[i] == elem) { + found = true; + } + if (found) { + g_list->elem_list[i] = g_list->elem_list[i+1]; + } + } + DCHECK_EQ(found, true); + g_list->num_used--; +} + +void GrowableListIteratorInit(GrowableList* g_list, + GrowableListIterator* iterator) +{ + iterator->list = g_list; + iterator->idx = 0; + iterator->size = g_list->num_used; +} + +uintptr_t GrowableListIteratorNext(GrowableListIterator* iterator) +{ + DCHECK_EQ(iterator->size, iterator->list->num_used); + if (iterator->idx == iterator->size) return 0; + return iterator->list->elem_list[iterator->idx++]; +} + +uintptr_t GrowableListGetElement(const GrowableList* g_list, size_t idx) +{ + DCHECK_LT(idx, g_list->num_used); + return g_list->elem_list[idx]; +} + +#ifdef WITH_MEMSTATS +/* Dump memory usage stats */ +void DumpMemStats(CompilationUnit* cu) +{ + uint32_t total = 0; + for (int i = 0; i < kNumAllocKinds; i++) { + total += cu->mstats->alloc_stats[i]; + } + if (total > (10 * 1024 * 1024)) { + LOG(INFO) << "MEMUSAGE: " << total << " : " + << PrettyMethod(cu->method_idx, *cu->dex_file); + LOG(INFO) << "insns_size: " << cu->insns_size; + if (cu->disable_dataflow) { + LOG(INFO) << " ** Dataflow disabled ** "; + } + LOG(INFO) << "===== Overall allocations"; + for (int i = 0; i < kNumAllocKinds; i++) { + LOG(INFO) << alloc_names[i] << std::setw(10) << + cu->mstats->alloc_stats[i]; + } + LOG(INFO) << "===== GrowableList allocations"; + for (int i = 0; i < kNumListKinds; i++) { + LOG(INFO) << list_names[i] + << " S:" << cu->mstats->list_sizes[i] + << ", W:" << cu->mstats->list_wasted[i] + << ", G:" << cu->mstats->list_grows[i] + << ", E:" << cu->mstats->list_max_elems[i]; + } + LOG(INFO) << "===== GrowableBitMap allocations"; + for (int i = 0; i < kNumBitMapKinds; i++) { + LOG(INFO) << bit_map_names[i] + << " S:" << cu->mstats->bit_map_sizes[i] + << ", W:" << cu->mstats->bit_map_wasted[i] + << ", G:" << cu->mstats->bit_map_grows[i]; + } + } +} +#endif + +/* Debug Utility - dump a compilation unit */ +void DumpCompilationUnit(CompilationUnit* cu) +{ + BasicBlock* bb; + const char* block_type_names[] = { + "Entry Block", + "Code Block", + "Exit Block", + "Exception Handling", + "Catch Block" + }; + + LOG(INFO) << "Compiling " << PrettyMethod(cu->method_idx, *cu->dex_file); + LOG(INFO) << cu->insns << " insns"; + LOG(INFO) << cu->num_blocks << " blocks in total"; + GrowableListIterator iterator; + + GrowableListIteratorInit(&cu->block_list, &iterator); + + while (true) { + bb = reinterpret_cast<BasicBlock*>(GrowableListIteratorNext(&iterator)); + if (bb == NULL) break; + LOG(INFO) << StringPrintf("Block %d (%s) (insn %04x - %04x%s)", + bb->id, + block_type_names[bb->block_type], + bb->start_offset, + bb->last_mir_insn ? bb->last_mir_insn->offset : bb->start_offset, + bb->last_mir_insn ? "" : " empty"); + if (bb->taken) { + LOG(INFO) << " Taken branch: block " << bb->taken->id + << "(0x" << std::hex << bb->taken->start_offset << ")"; + } + if (bb->fall_through) { + LOG(INFO) << " Fallthrough : block " << bb->fall_through->id + << " (0x" << std::hex << bb->fall_through->start_offset << ")"; + } + } +} + +static uint32_t check_masks[32] = { + 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, + 0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, + 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000, + 0x00008000, 0x00010000, 0x00020000, 0x00040000, 0x00080000, + 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000, + 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, + 0x40000000, 0x80000000 }; + +/* + * Allocate a bit vector with enough space to hold at least the specified + * number of bits. + * + * NOTE: memory is allocated from the compiler arena. + */ +ArenaBitVector* AllocBitVector(CompilationUnit* cu, + unsigned int start_bits, bool expandable, + oat_bit_map_kind kind) +{ + ArenaBitVector* bv; + unsigned int count; + + DCHECK_EQ(sizeof(bv->storage[0]), 4U); /* assuming 32-bit units */ + + bv = static_cast<ArenaBitVector*>(NewMem(cu, sizeof(ArenaBitVector), false, + kAllocGrowableBitMap)); + + count = (start_bits + 31) >> 5; + + bv->storage_size = count; + bv->expandable = expandable; + bv->storage = static_cast<uint32_t*>(NewMem(cu, count * sizeof(uint32_t), true, + kAllocGrowableBitMap)); +#ifdef WITH_MEMSTATS + bv->kind = kind; + cu->mstats->bit_map_sizes[kind] += count * sizeof(uint32_t); +#endif + return bv; +} + +/* + * Determine whether or not the specified bit is set. + */ +bool IsBitSet(const ArenaBitVector* p_bits, unsigned int num) +{ + DCHECK_LT(num, p_bits->storage_size * sizeof(uint32_t) * 8); + + unsigned int val = p_bits->storage[num >> 5] & check_masks[num & 0x1f]; + return (val != 0); +} + +/* + * Mark all bits bit as "clear". + */ +void ClearAllBits(ArenaBitVector* p_bits) +{ + unsigned int count = p_bits->storage_size; + memset(p_bits->storage, 0, count * sizeof(uint32_t)); +} + +/* + * Mark the specified bit as "set". + * + * Returns "false" if the bit is outside the range of the vector and we're + * not allowed to expand. + * + * NOTE: memory is allocated from the compiler arena. + */ +bool SetBit(CompilationUnit* cu, ArenaBitVector* p_bits, unsigned int num) +{ + if (num >= p_bits->storage_size * sizeof(uint32_t) * 8) { + if (!p_bits->expandable) { + LOG(FATAL) << "Can't expand"; + } + + /* Round up to word boundaries for "num+1" bits */ + unsigned int new_size = (num + 1 + 31) >> 5; + DCHECK_GT(new_size, p_bits->storage_size); + uint32_t *new_storage = static_cast<uint32_t*>(NewMem(cu, new_size * sizeof(uint32_t), false, + kAllocGrowableBitMap)); + memcpy(new_storage, p_bits->storage, p_bits->storage_size * sizeof(uint32_t)); + memset(&new_storage[p_bits->storage_size], 0, + (new_size - p_bits->storage_size) * sizeof(uint32_t)); +#ifdef WITH_MEMSTATS + cu->mstats->bit_map_wasted[p_bits->kind] += + p_bits->storage_size * sizeof(uint32_t); + cu->mstats->bit_map_sizes[p_bits->kind] += new_size * sizeof(uint32_t); + cu->mstats->bit_map_grows[p_bits->kind]++; +#endif + p_bits->storage = new_storage; + p_bits->storage_size = new_size; + } + + p_bits->storage[num >> 5] |= check_masks[num & 0x1f]; + return true; +} + +/* + * Mark the specified bit as "unset". + * + * Returns "false" if the bit is outside the range of the vector and we're + * not allowed to expand. + * + * NOTE: memory is allocated from the compiler arena. + */ +bool ClearBit(ArenaBitVector* p_bits, unsigned int num) +{ + if (num >= p_bits->storage_size * sizeof(uint32_t) * 8) { + LOG(FATAL) << "Attempt to clear a bit not set in the vector yet";; + } + + p_bits->storage[num >> 5] &= ~check_masks[num & 0x1f]; + return true; +} + +/* Initialize the iterator structure */ +void BitVectorIteratorInit(ArenaBitVector* p_bits, + ArenaBitVectorIterator* iterator) +{ + iterator->p_bits = p_bits; + iterator->bit_size = p_bits->storage_size * sizeof(uint32_t) * 8; + iterator->idx = 0; +} + +/* + * If the vector sizes don't match, log an error and abort. + */ +static void CheckSizes(const ArenaBitVector* bv1, const ArenaBitVector* bv2) +{ + if (bv1->storage_size != bv2->storage_size) { + LOG(FATAL) << "Mismatched vector sizes (" << bv1->storage_size + << ", " << bv2->storage_size << ")"; + } +} + +/* + * Copy a whole vector to the other. Only do that when the both vectors have + * the same size. + */ +void CopyBitVector(ArenaBitVector* dest, const ArenaBitVector* src) +{ + /* if dest is expandable and < src, we could expand dest to match */ + CheckSizes(dest, src); + + memcpy(dest->storage, src->storage, sizeof(uint32_t) * dest->storage_size); +} + +/* + * Intersect two bit vectors and store the result to the dest vector. + */ + +bool IntersectBitVectors(ArenaBitVector* dest, const ArenaBitVector* src1, + const ArenaBitVector* src2) +{ + DCHECK(src1 != NULL); + DCHECK(src2 != NULL); + if (dest->storage_size != src1->storage_size || + dest->storage_size != src2->storage_size || + dest->expandable != src1->expandable || + dest->expandable != src2->expandable) + return false; + + unsigned int idx; + for (idx = 0; idx < dest->storage_size; idx++) { + dest->storage[idx] = src1->storage[idx] & src2->storage[idx]; + } + return true; +} + +/* + * Unify two bit vectors and store the result to the dest vector. + */ +bool UnifyBitVetors(ArenaBitVector* dest, const ArenaBitVector* src1, + const ArenaBitVector* src2) +{ + DCHECK(src1 != NULL); + DCHECK(src2 != NULL); + if (dest->storage_size != src1->storage_size || + dest->storage_size != src2->storage_size || + dest->expandable != src1->expandable || + dest->expandable != src2->expandable) + return false; + + unsigned int idx; + for (idx = 0; idx < dest->storage_size; idx++) { + dest->storage[idx] = src1->storage[idx] | src2->storage[idx]; + } + return true; +} + +/* + * Return true if any bits collide. Vectors must be same size. + */ +bool TestBitVectors(const ArenaBitVector* src1, + const ArenaBitVector* src2) +{ + DCHECK_EQ(src1->storage_size, src2->storage_size); + for (uint32_t idx = 0; idx < src1->storage_size; idx++) { + if (src1->storage[idx] & src2->storage[idx]) return true; + } + return false; +} + +/* + * Compare two bit vectors and return true if difference is seen. + */ +bool CompareBitVectors(const ArenaBitVector* src1, + const ArenaBitVector* src2) +{ + if (src1->storage_size != src2->storage_size || + src1->expandable != src2->expandable) + return true; + + unsigned int idx; + for (idx = 0; idx < src1->storage_size; idx++) { + if (src1->storage[idx] != src2->storage[idx]) return true; + } + return false; +} + +/* + * Count the number of bits that are set. + */ +int CountSetBits(const ArenaBitVector* p_bits) +{ + unsigned int word; + unsigned int count = 0; + + for (word = 0; word < p_bits->storage_size; word++) { + uint32_t val = p_bits->storage[word]; + + if (val != 0) { + if (val == 0xffffffff) { + count += 32; + } else { + /* count the number of '1' bits */ + while (val != 0) { + val &= val - 1; + count++; + } + } + } + } + + return count; +} + +/* Return the next position set to 1. -1 means end-of-element reached */ +int BitVectorIteratorNext(ArenaBitVectorIterator* iterator) +{ + ArenaBitVector* p_bits = iterator->p_bits; + uint32_t bit_index = iterator->idx; + uint32_t bit_size = iterator->bit_size; + + DCHECK_EQ(bit_size, p_bits->storage_size * sizeof(uint32_t) * 8); + + if (bit_index >= bit_size) return -1; + + uint32_t word_index = bit_index >> 5; + uint32_t end_word_index = bit_size >> 5; + uint32_t* storage = p_bits->storage; + uint32_t word = storage[word_index++]; + + // Mask out any bits in the first word we've already considered + word &= ~((1 << (bit_index & 0x1f))-1); + + for (; word_index <= end_word_index;) { + uint32_t bit_pos = bit_index & 0x1f; + if (word == 0) { + bit_index += (32 - bit_pos); + word = storage[word_index++]; + continue; + } + for (; bit_pos < 32; bit_pos++) { + if (word & (1 << bit_pos)) { + iterator->idx = bit_index + 1; + return bit_index; + } + bit_index++; + } + word = storage[word_index++]; + } + iterator->idx = iterator->bit_size; + return -1; +} + +/* + * Mark specified number of bits as "set". Cannot set all bits like ClearAll + * since there might be unused bits - setting those to one will confuse the + * iterator. + */ +void SetInitialBits(ArenaBitVector* p_bits, unsigned int num_bits) +{ + unsigned int idx; + DCHECK_LE(((num_bits + 31) >> 5), p_bits->storage_size); + for (idx = 0; idx < (num_bits >> 5); idx++) { + p_bits->storage[idx] = -1; + } + unsigned int rem_num_bits = num_bits & 0x1f; + if (rem_num_bits) { + p_bits->storage[idx] = (1 << rem_num_bits) - 1; + } +} + +void GetBlockName(BasicBlock* bb, char* name) +{ + switch (bb->block_type) { + case kEntryBlock: + snprintf(name, BLOCK_NAME_LEN, "entry_%d", bb->id); + break; + case kExitBlock: + snprintf(name, BLOCK_NAME_LEN, "exit_%d", bb->id); + break; + case kDalvikByteCode: + snprintf(name, BLOCK_NAME_LEN, "block%04x_%d", bb->start_offset, bb->id); + break; + case kExceptionHandling: + snprintf(name, BLOCK_NAME_LEN, "exception%04x_%d", bb->start_offset, + bb->id); + break; + default: + snprintf(name, BLOCK_NAME_LEN, "_%d", bb->id); + break; + } +} + +const char* GetShortyFromTargetIdx(CompilationUnit *cu, int target_idx) +{ + const DexFile::MethodId& method_id = cu->dex_file->GetMethodId(target_idx); + return cu->dex_file->GetShorty(method_id.proto_idx_); +} + +/* Allocate a new basic block */ +BasicBlock* NewMemBB(CompilationUnit* cu, BBType block_type, int block_id) +{ + BasicBlock* bb = static_cast<BasicBlock*>(NewMem(cu, sizeof(BasicBlock), true, kAllocBB)); + bb->block_type = block_type; + bb->id = block_id; + bb->predecessors = static_cast<GrowableList*> + (NewMem(cu, sizeof(GrowableList), false, kAllocPredecessors)); + CompilerInitGrowableList(cu, bb->predecessors, + (block_type == kExitBlock) ? 2048 : 2, + kListPredecessors); + cu->block_id_map.Put(block_id, block_id); + return bb; +} + +/* Insert an MIR instruction to the end of a basic block */ +void AppendMIR(BasicBlock* bb, MIR* mir) +{ + if (bb->first_mir_insn == NULL) { + DCHECK(bb->last_mir_insn == NULL); + bb->last_mir_insn = bb->first_mir_insn = mir; + mir->prev = mir->next = NULL; + } else { + bb->last_mir_insn->next = mir; + mir->prev = bb->last_mir_insn; + mir->next = NULL; + bb->last_mir_insn = mir; + } +} + +/* Insert an MIR instruction to the head of a basic block */ +void PrependMIR(BasicBlock* bb, MIR* mir) +{ + if (bb->first_mir_insn == NULL) { + DCHECK(bb->last_mir_insn == NULL); + bb->last_mir_insn = bb->first_mir_insn = mir; + mir->prev = mir->next = NULL; + } else { + bb->first_mir_insn->prev = mir; + mir->next = bb->first_mir_insn; + mir->prev = NULL; + bb->first_mir_insn = mir; + } +} + +/* Insert a MIR instruction after the specified MIR */ +void InsertMIRAfter(BasicBlock* bb, MIR* current_mir, MIR* new_mir) +{ + new_mir->prev = current_mir; + new_mir->next = current_mir->next; + current_mir->next = new_mir; + + if (new_mir->next) { + /* Is not the last MIR in the block */ + new_mir->next->prev = new_mir; + } else { + /* Is the last MIR in the block */ + bb->last_mir_insn = new_mir; + } +} + +/* + * Append an LIR instruction to the LIR list maintained by a compilation + * unit + */ +void AppendLIR(CompilationUnit *cu, LIR* lir) +{ + if (cu->first_lir_insn == NULL) { + DCHECK(cu->last_lir_insn == NULL); + cu->last_lir_insn = cu->first_lir_insn = lir; + lir->prev = lir->next = NULL; + } else { + cu->last_lir_insn->next = lir; + lir->prev = cu->last_lir_insn; + lir->next = NULL; + cu->last_lir_insn = lir; + } +} + +/* + * Insert an LIR instruction before the current instruction, which cannot be the + * first instruction. + * + * prev_lir <-> new_lir <-> current_lir + */ +void InsertLIRBefore(LIR* current_lir, LIR* new_lir) +{ + DCHECK(current_lir->prev != NULL); + LIR *prev_lir = current_lir->prev; + + prev_lir->next = new_lir; + new_lir->prev = prev_lir; + new_lir->next = current_lir; + current_lir->prev = new_lir; +} + +/* + * Insert an LIR instruction after the current instruction, which cannot be the + * first instruction. + * + * current_lir -> new_lir -> old_next + */ +void InsertLIRAfter(LIR* current_lir, LIR* new_lir) +{ + new_lir->prev = current_lir; + new_lir->next = current_lir->next; + current_lir->next = new_lir; + new_lir->next->prev = new_lir; +} + +} // namespace art |