diff options
author | buzbee <buzbee@google.com> | 2010-08-04 15:25:06 -0700 |
---|---|---|
committer | buzbee <buzbee@google.com> | 2010-08-04 15:59:55 -0700 |
commit | bff121aa3e5d3c34caf837227cb00a46bf3f1966 (patch) | |
tree | 749877c971544c3518c00428c76d2028d7ee2402 /vm/compiler/codegen/arm/Assemble.c | |
parent | 4a41958266fb432629dea30832f4b3194667ba99 (diff) | |
download | android_dalvik-bff121aa3e5d3c34caf837227cb00a46bf3f1966.tar.gz android_dalvik-bff121aa3e5d3c34caf837227cb00a46bf3f1966.tar.bz2 android_dalvik-bff121aa3e5d3c34caf837227cb00a46bf3f1966.zip |
JIT: Reworked the assembler to be smarter about short instruction forms
Previously, the JIT wasn't generating short-form compare and branch on
zero/not zero instructions for Thumb2. The reason was that these only
allow a 1-byte displacement, and when they didn't reach the assembler would
abort the trace, split it in half and try again. This change re-enables
cbz, cbnz generation and introduces a relatively lightweight retry
mechanism.
Also includes changes for Thumb2 to always generate large displacement
literal loads and conditional branches to minimize the number of retry
attempts.
Change-Id: Icf066836fad203f5c0fcbbb2ae8e1aa73d1cf816
Diffstat (limited to 'vm/compiler/codegen/arm/Assemble.c')
-rw-r--r-- | vm/compiler/codegen/arm/Assemble.c | 90 |
1 files changed, 59 insertions, 31 deletions
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c index c1b08a3cc..4f975b363 100644 --- a/vm/compiler/codegen/arm/Assemble.c +++ b/vm/compiler/codegen/arm/Assemble.c @@ -20,9 +20,12 @@ #include "../../CompilerInternals.h" #include "ArmLIR.h" +#include "Codegen.h" #include <unistd.h> /* for cacheflush */ #include <sys/mman.h> /* for protection change */ +#define MAX_ASSEMBLER_RETRIES 10 + /* * opcode: ArmOpCode enum * skeleton: pre-designated bit-pattern for this opcode @@ -914,8 +917,14 @@ static int jitTraceDescriptionSize(const JitTraceDescription *desc) return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun)); } -/* Return TRUE if error happens */ -static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr) +/* + * Assemble the LIR into binary instruction format. Note that we may + * discover that pc-relative displacements may not fit the selected + * instruction. In those cases we will try to substitute a new code + * sequence or request that the trace be shortened and retried. + */ +static AssemblerStatus assembleInstructions(CompilationUnit *cUnit, + intptr_t startAddr) { short *bufferAddr = (short *) cUnit->codeBuffer; ArmLIR *lir; @@ -952,9 +961,9 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr) dvmCompilerAbort(cUnit); } if ((lir->opCode == kThumb2LdrPcRel12) && (delta > 4091)) { - return true; + return kRetryHalve; } else if (delta > 1020) { - return true; + return kRetryHalve; } if (lir->opCode == kThumb2Vldrs) { lir->operands[2] = delta >> 2; @@ -968,11 +977,23 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr) intptr_t target = targetLIR->generic.offset; int delta = target - pc; if (delta > 126 || delta < 0) { - /* - * TODO: allow multiple kinds of assembler failure to allow - * change of code patterns when things don't fit. - */ - return true; + /* Convert to cmp rx,#0 / b[eq/ne] tgt pair */ + ArmLIR *newInst = dvmCompilerNew(sizeof(ArmLIR), true); + /* Make new branch instruction and insert after */ + newInst->opCode = kThumbBCond; + newInst->operands[0] = 0; + newInst->operands[1] = (lir->opCode == kThumb2Cbz) ? + kArmCondEq : kArmCondNe; + newInst->generic.target = lir->generic.target; + dvmCompilerSetupResourceMasks(newInst); + dvmCompilerInsertLIRAfter((LIR *)lir, (LIR *)newInst); + /* Convert the cb[n]z to a cmp rx, #0 ] */ + lir->opCode = kThumbCmpRI8; + lir->operands[0] = lir->operands[1]; + lir->operands[1] = 0; + lir->generic.target = 0; + dvmCompilerSetupResourceMasks(lir); + return kRetryAll; } else { lir->operands[1] = delta >> 1; } @@ -983,7 +1004,7 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr) intptr_t target = targetLIR->generic.offset; int delta = target - pc; if ((lir->opCode == kThumbBCond) && (delta > 254 || delta < -256)) { - return true; + return kRetryHalve; } lir->operands[0] = delta >> 1; } else if (lir->opCode == kThumbBUncond) { @@ -1029,18 +1050,12 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr) bits |= value; break; case kFmtBrOffset: - /* - * NOTE: branch offsets are not handled here, but - * in the main assembly loop (where label values - * are known). For reference, here is what the - * encoder handing would be: - value = ((operand & 0x80000) >> 19) << 26; - value |= ((operand & 0x40000) >> 18) << 11; - value |= ((operand & 0x20000) >> 17) << 13; - value |= ((operand & 0x1f800) >> 11) << 16; - value |= (operand & 0x007ff); - bits |= value; - */ + value = ((operand & 0x80000) >> 19) << 26; + value |= ((operand & 0x40000) >> 18) << 11; + value |= ((operand & 0x20000) >> 17) << 13; + value |= ((operand & 0x1f800) >> 11) << 16; + value |= (operand & 0x007ff); + bits |= value; break; case kFmtShift5: value = ((operand & 0x1c) >> 2) << 12; @@ -1117,7 +1132,7 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr) } *bufferAddr++ = bits & 0xffff; } - return false; + return kSuccess; } #if defined(SIGNATURE_BREAKPOINT) @@ -1277,16 +1292,29 @@ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info) return; } - bool assemblerFailure = assembleInstructions( - cUnit, (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed); - /* - * Currently the only reason that can cause the assembler to fail is due to - * trace length - cut it in half and retry. + * Attempt to assemble the trace. Note that assembleInstructions + * may rewrite the code sequence and request a retry. */ - if (assemblerFailure) { - cUnit->halveInstCount = true; - return; + cUnit->assemblerStatus = assembleInstructions(cUnit, + (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed); + + switch(cUnit->assemblerStatus) { + case kSuccess: + break; + case kRetryAll: + if (cUnit->assemblerRetries < MAX_ASSEMBLER_RETRIES) { + return; + } + /* Too many retries - reset and try cutting the trace in half */ + cUnit->assemblerRetries = 0; + cUnit->assemblerStatus = kRetryHalve; + return; + case kRetryHalve: + return; + default: + LOGE("Unexpected assembler status: %d", cUnit->assemblerStatus); + dvmAbort(); } #if defined(SIGNATURE_BREAKPOINT) |