summaryrefslogtreecommitdiff
path: root/src/compiler/codegen/CodegenUtil.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/codegen/CodegenUtil.cc')
-rw-r--r--src/compiler/codegen/CodegenUtil.cc235
1 files changed, 235 insertions, 0 deletions
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<uint16_t>&buf, int data) {
+ buf.push_back( data & 0xffff);
+ buf.push_back( (data >> 16) & 0xffff);
+}
+
+void alignBuffer(std::vector<uint16_t>&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