From e3acd07f28d5625062b599c2817cb5f7a53f54a9 Mon Sep 17 00:00:00 2001 From: buzbee Date: Sat, 25 Feb 2012 17:03:10 -0800 Subject: Multi-target support This CL represents a step towards splitting out the target dependent and target independent portions of the compiler, and also adds in the beginning of a MIPS compiler based on the MIPS AOSP Jit submission. More polish is clearly needed, but the split is here probably pretty close. The MIPS code will not compile at this point (and there is no makefile target at present), but it's pretty close. There should be no changes in functionality of the Arm compiler in this CL - just moved stuff around. Change-Id: Ia66b2847e22644a1ec63e66bf5f2fee722f963d4 --- src/compiler/codegen/CodegenUtil.cc | 235 ++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 src/compiler/codegen/CodegenUtil.cc (limited to 'src/compiler/codegen/CodegenUtil.cc') diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc new file mode 100644 index 0000000000..1f05a17a65 --- /dev/null +++ b/src/compiler/codegen/CodegenUtil.cc @@ -0,0 +1,235 @@ +/* + * 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. + */ + +namespace art { + +STATIC void pushWord(std::vector&buf, int data) { + buf.push_back( data & 0xffff); + buf.push_back( (data >> 16) & 0xffff); +} + +void alignBuffer(std::vector&buf, size_t offset) { + while (buf.size() < (offset/2)) + buf.push_back(0); +} + +/* Write the literal pool to the output stream */ +STATIC void installLiteralPools(CompilationUnit* cUnit) +{ + alignBuffer(cUnit->codeBuffer, cUnit->dataOffset); + TGT_LIR* dataLIR = (TGT_LIR*) cUnit->literalList; + while (dataLIR != NULL) { + pushWord(cUnit->codeBuffer, dataLIR->operands[0]); + dataLIR = NEXT_LIR(dataLIR); + } +} + +/* Write the switch tables to the output stream */ +STATIC void installSwitchTables(CompilationUnit* cUnit) +{ + GrowableListIterator iterator; + oatGrowableListIteratorInit(&cUnit->switchTables, &iterator); + while (true) { + SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext( + &iterator); + if (tabRec == NULL) break; + alignBuffer(cUnit->codeBuffer, tabRec->offset); + int bxOffset = tabRec->bxInst->generic.offset + 4; + if (cUnit->printMe) { + LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset; + } + if (tabRec->table[0] == kSparseSwitchSignature) { + int* keys = (int*)&(tabRec->table[2]); + for (int elems = 0; elems < tabRec->table[1]; elems++) { + int disp = tabRec->targets[elems]->generic.offset - bxOffset; + if (cUnit->printMe) { + LOG(INFO) << " Case[" << elems << "] key: 0x" << + std::hex << keys[elems] << ", disp: 0x" << + std::hex << disp; + } + pushWord(cUnit->codeBuffer, keys[elems]); + pushWord(cUnit->codeBuffer, + tabRec->targets[elems]->generic.offset - bxOffset); + } + } else { + DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature); + for (int elems = 0; elems < tabRec->table[1]; elems++) { + int disp = tabRec->targets[elems]->generic.offset - bxOffset; + if (cUnit->printMe) { + LOG(INFO) << " Case[" << elems << "] disp: 0x" << + std::hex << disp; + } + pushWord(cUnit->codeBuffer, + tabRec->targets[elems]->generic.offset - bxOffset); + } + } + } +} + +/* Write the fill array dta to the output stream */ +STATIC void installFillArrayData(CompilationUnit* cUnit) +{ + GrowableListIterator iterator; + oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator); + while (true) { + FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext( + &iterator); + if (tabRec == NULL) break; + alignBuffer(cUnit->codeBuffer, tabRec->offset); + for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) { + cUnit->codeBuffer.push_back( tabRec->table[i]); + } + } +} + +STATIC int assignLiteralOffsetCommon(LIR* lir, int offset) +{ + for (;lir != NULL; lir = lir->next) { + lir->offset = offset; + offset += 4; + } + return offset; +} + +STATIC void createMappingTable(CompilationUnit* cUnit) +{ + TGT_LIR* tgtLIR; + int currentDalvikOffset = -1; + + for (tgtLIR = (TGT_LIR *) cUnit->firstLIRInsn; + tgtLIR; + tgtLIR = NEXT_LIR(tgtLIR)) { + if ((tgtLIR->opcode >= 0) && !tgtLIR->flags.isNop && + (currentDalvikOffset != tgtLIR->generic.dalvikOffset)) { + // Changed - need to emit a record + cUnit->mappingTable.push_back(tgtLIR->generic.offset); + cUnit->mappingTable.push_back(tgtLIR->generic.dalvikOffset); + currentDalvikOffset = tgtLIR->generic.dalvikOffset; + } + } +} + +/* Determine the offset of each literal field */ +STATIC int assignLiteralOffset(CompilationUnit* cUnit, int offset) +{ + offset = assignLiteralOffsetCommon(cUnit->literalList, offset); + return offset; +} + +STATIC int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset) +{ + GrowableListIterator iterator; + oatGrowableListIteratorInit(&cUnit->switchTables, &iterator); + while (true) { + SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext( + &iterator); + if (tabRec == NULL) break; + tabRec->offset = offset; + if (tabRec->table[0] == kSparseSwitchSignature) { + offset += tabRec->table[1] * (sizeof(int) * 2); + } else { + DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature); + offset += tabRec->table[1] * sizeof(int); + } + } + return offset; +} + +STATIC int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset) +{ + GrowableListIterator iterator; + oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator); + while (true) { + FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext( + &iterator); + if (tabRec == NULL) break; + tabRec->offset = offset; + offset += tabRec->size; + // word align + offset = (offset + 3) & ~3; + } + return offset; +} + +/* + * Walk the compilation unit and assign offsets to instructions + * and literals and compute the total size of the compiled unit. + */ +void oatAssignOffsets(CompilationUnit* cUnit) +{ + int offset = oatAssignInsnOffsets(cUnit); + + /* Const values have to be word aligned */ + offset = (offset + 3) & ~3; + + /* Set up offsets for literals */ + cUnit->dataOffset = offset; + + offset = assignLiteralOffset(cUnit, offset); + + offset = assignSwitchTablesOffset(cUnit, offset); + + offset = assignFillArrayDataOffset(cUnit, offset); + + cUnit->totalSize = offset; +} + +/* + * Go over each instruction in the list and calculate the offset from the top + * before sending them off to the assembler. If out-of-range branch distance is + * seen rearrange the instructions a bit to correct it. + */ +void oatAssembleLIR(CompilationUnit* cUnit) +{ + oatAssignOffsets(cUnit); + /* + * Assemble here. Note that we generate code with optimistic assumptions + * and if found now to work, we'll have to redo the sequence and retry. + */ + + while (true) { + AssemblerStatus res = oatAssembleInstructions(cUnit, 0); + if (res == kSuccess) { + break; + } else { + cUnit->assemblerRetries++; + if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) { + LOG(FATAL) << "Assembler error - too many retries"; + } + // Redo offsets and try again + oatAssignOffsets(cUnit); + cUnit->codeBuffer.clear(); + } + } + + // Install literals + installLiteralPools(cUnit); + + // Install switch tables + installSwitchTables(cUnit); + + // Install fill array data + installFillArrayData(cUnit); + + /* + * Create the mapping table + */ + createMappingTable(cUnit); +} + + + +} // namespace art -- cgit v1.2.3-59-g8ed1b