TR::Register *OMR::Power::Linkage::pushLongArg(TR::Node *child) { TR::Register *pushRegister = NULL; if (child->getRegister() == NULL && child->getOpCode().isLoadConst()) { if (TR::Compiler->target.is64Bit()) { pushRegister = self()->cg()->allocateRegister(); loadConstant(self()->cg(), child, child->getLongInt(), pushRegister); } else { TR::Register *lowRegister = self()->cg()->allocateRegister(); TR::Register *highRegister = self()->cg()->allocateRegister(); pushRegister = self()->cg()->allocateRegisterPair(lowRegister, highRegister); loadConstant(self()->cg(), child, child->getLongIntLow(), lowRegister); loadConstant(self()->cg(), child, child->getLongIntHigh(), highRegister); } child->setRegister(pushRegister); } else { pushRegister = self()->cg()->evaluate(child); } self()->cg()->decReferenceCount(child); return pushRegister; }
static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir) { int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode); int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn | kInstrCanThrow; //If already optimized out, just ignore if (mir->dalvikInsn.opcode == OP_NOP) return; //Ugly, but necessary. Flush all Dalvik regs so Interp can find them dvmCompilerFlushAllRegs(cUnit); if ((mir->next == NULL) || (flags & flagsToCheck)) { genPuntToInterp(cUnit, mir->offset); return; } int entryAddr = offsetof(Thread, jitToInterpEntries.dvmJitToInterpSingleStep); loadWordDisp(cUnit, rEBP, 0, rECX); // Get glue loadWordDisp(cUnit, rECX, entryAddr, rEAX); // rEAX<- entry address /* rPC = dalvik pc */ loadConstant(cUnit, rPC, (int) (cUnit->method->insns + mir->offset)); /* rECX = dalvik pc of following instruction */ loadConstant(cUnit, rECX, (int) (cUnit->method->insns + mir->next->offset)); /* Pass on the stack */ storeWordDisp(cUnit, rESP, OUT_ARG0, rECX); opReg(cUnit, kOpCall, rEAX); }
/* * 64-bit 3way compare function. * mov r7, #-1 * cmp op1hi, op2hi * blt done * bgt flip * sub r7, op1lo, op2lo (treat as unsigned) * beq done * ite hi * mov(hi) r7, #-1 * mov(!hi) r7, #1 * flip: * neg r7 * done: */ static void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2) { RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change ArmLIR *target1; ArmLIR *target2; rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); rlTemp.lowReg = dvmCompilerAllocTemp(cUnit); loadConstant(cUnit, rlTemp.lowReg, -1); opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg); ArmLIR *branch1 = opCondBranch(cUnit, kArmCondLt); ArmLIR *branch2 = opCondBranch(cUnit, kArmCondGt); opRegRegReg(cUnit, kOpSub, rlTemp.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); ArmLIR *branch3 = opCondBranch(cUnit, kArmCondEq); genIT(cUnit, kArmCondHi, "E"); newLIR2(cUnit, kThumb2MovImmShift, rlTemp.lowReg, modifiedImmediate(-1)); loadConstant(cUnit, rlTemp.lowReg, 1); genBarrier(cUnit); target2 = newLIR0(cUnit, kArmPseudoTargetLabel); target2->defMask = -1; opRegReg(cUnit, kOpNeg, rlTemp.lowReg, rlTemp.lowReg); target1 = newLIR0(cUnit, kArmPseudoTargetLabel); target1->defMask = -1; storeValue(cUnit, rlDest, rlTemp); branch1->generic.target = (LIR *)target1; branch2->generic.target = (LIR *)target2; branch3->generic.target = branch1->generic.target; }
/* * Rebuild the interpreter frame then punt to the interpreter to execute * instruction at specified PC. * * Currently parameters are passed to the current frame, so we just need to * grow the stack save area above it, fill certain fields in StackSaveArea and * Thread that are skipped during whole-method invocation (specified below), * then return to the interpreter. * * StackSaveArea: * - prevSave * - prevFrame * - savedPc * - returnAddr * - method * * Thread: * - method * - methodClassDex * - curFrame */ static void genMethodInflateAndPunt(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb) { int oldStackSave = r0; int newStackSave = r1; int oldFP = r2; int savedPC = r3; int currentPC = r4PC; int returnAddr = r7; int method = r8; int pDvmDex = r9; /* * TODO: check whether to raise the stack overflow exception when growing * the stack save area. */ /* Send everything to home location */ dvmCompilerFlushAllRegs(cUnit); /* oldStackSave = r5FP + sizeof(current frame) */ opRegRegImm(cUnit, kOpAdd, oldStackSave, r5FP, cUnit->method->registersSize * 4); /* oldFP = oldStackSave + sizeof(stackSaveArea) */ opRegRegImm(cUnit, kOpAdd, oldFP, oldStackSave, sizeof(StackSaveArea)); /* newStackSave = r5FP - sizeof(StackSaveArea) */ opRegRegImm(cUnit, kOpSub, newStackSave, r5FP, sizeof(StackSaveArea)); loadWordDisp(cUnit, r13sp, 0, savedPC); loadConstant(cUnit, currentPC, (int) (cUnit->method->insns + mir->offset)); loadConstant(cUnit, method, (int) cUnit->method); loadConstant(cUnit, pDvmDex, (int) cUnit->method->clazz->pDvmDex); #ifdef EASY_GDB /* newStackSave->prevSave = oldStackSave */ storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevSave), oldStackSave); #endif /* newStackSave->prevSave = oldStackSave */ storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevFrame), oldFP); /* newStackSave->savedPc = savedPC */ storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, savedPc), savedPC); /* return address */ loadConstant(cUnit, returnAddr, 0); storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, returnAddr), returnAddr); /* newStackSave->method = method */ storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, method), method); /* thread->method = method */ storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, method), method); /* thread->interpSave.curFrame = current FP */ storeWordDisp(cUnit, r6SELF, offsetof(Thread, interpSave.curFrame), r5FP); /* thread->methodClassDex = pDvmDex */ storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, methodClassDex), pDvmDex); /* Restore the stack pointer */ opRegImm(cUnit, kOpAdd, r13sp, 16); genPuntToInterp(cUnit, mir->offset); }
static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2) { bool isDouble; int defaultResult; bool ltNaNBias; RegLocation rlResult; switch(mir->dalvikInsn.opCode) { case OP_CMPL_FLOAT: isDouble = false; defaultResult = -1; break; case OP_CMPG_FLOAT: isDouble = false; defaultResult = 1; break; case OP_CMPL_DOUBLE: isDouble = true; defaultResult = -1; break; case OP_CMPG_DOUBLE: isDouble = true; defaultResult = 1; break; default: return true; } if (isDouble) { rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg); rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg); dvmCompilerClobberSReg(cUnit, rlDest.sRegLow); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); loadConstant(cUnit, rlResult.lowReg, defaultResult); newLIR2(cUnit, kThumb2Vcmpd, S2D(rlSrc1.lowReg, r1Src2.highReg), S2D(rlSrc2.lowReg, rlSrc2.highReg)); } else { rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg); rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg); dvmCompilerClobberSReg(cUnit, rlDest.sRegLow); rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); loadConstant(cUnit, rlResult.lowReg, defaultResult); newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg); } assert(!FPREG(rlResult.lowReg)); newLIR0(cUnit, kThumb2Fmstat); genIT(cUnit, (defaultResult == -1) ? kArmCondGt : kArmCondMi, ""); newLIR2(cUnit, kThumb2MovImmShift, rlResult.lowReg, modifiedImmediate(-defaultResult)); // Must not alter ccodes genIT(cUnit, kArmCondEq, ""); loadConstant(cUnit, rlResult.lowReg, 0); storeValue(cUnit, rlDest, rlResult); return false; }
/* * For monitor unlock, we don't have to use ldrex/strex. Once * we've determined that the lock is thin and that we own it with * a zero recursion count, it's safe to punch it back to the * initial, unlock thin state with a store word. */ static void genMonitorExit(CompilationUnit *cUnit, MIR *mir) { RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); ArmLIR *target; ArmLIR *branch; ArmLIR *hopTarget; ArmLIR *hopBranch; assert(LW_SHAPE_THIN == 0); loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj dvmCompilerLockAllTemps(cUnit); // Prepare for explicit register usage dvmCompilerFreeTemp(cUnit, r4PC); // Free up r4 for general use genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL); loadWordDisp(cUnit, r1, offsetof(Object, lock), r2); // Get object->lock loadWordDisp(cUnit, r6SELF, offsetof(Thread, threadId), r3); // Get threadId // Is lock unheld on lock or held by us (==threadId) on unlock? opRegRegImm(cUnit, kOpAnd, r7, r2, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT)); opRegImm(cUnit, kOpLsl, r3, LW_LOCK_OWNER_SHIFT); // Align owner newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1); opRegReg(cUnit, kOpSub, r2, r3); hopBranch = opCondBranch(cUnit, kArmCondNe); dvmCompilerGenMemBarrier(cUnit, kSY); storeWordDisp(cUnit, r1, offsetof(Object, lock), r7); branch = opNone(cUnit, kOpUncondBr); hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel); hopTarget->defMask = ENCODE_ALL; hopBranch->generic.target = (LIR *)hopTarget; // Export PC (part 1) loadConstant(cUnit, r3, (int) (cUnit->method->insns + mir->offset)); LOAD_FUNC_ADDR(cUnit, r7, (int)dvmUnlockObject); genRegCopy(cUnit, r0, r6SELF); // Export PC (part 2) newLIR3(cUnit, kThumb2StrRRI8Predec, r3, r5FP, sizeof(StackSaveArea) - offsetof(StackSaveArea, xtra.currentPc)); opReg(cUnit, kOpBlx, r7); /* Did we throw? */ ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset + dexGetWidthFromOpcode(OP_MONITOR_EXIT))); genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); // Resume here target = newLIR0(cUnit, kArmPseudoTargetLabel); target->defMask = ENCODE_ALL; branch->generic.target = (LIR *)target; branchOver->generic.target = (LIR *) target; }
/* * Handle simple case (thin lock) inline. If it's complicated, bail * out to the heavyweight lock/unlock routines. We'll use dedicated * registers here in order to be in the right position in case we * to bail to dvm[Lock/Unlock]Object(self, object) * * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object * r1 -> object [arg1 for dvm[Lock/Unlock]Object * r2 -> intial contents of object->lock, later result of strex * r3 -> self->threadId * r7 -> temp to hold new lock value [unlock only] * r4 -> allow to be used by utilities as general temp * * The result of the strex is 0 if we acquire the lock. * * See comments in Sync.c for the layout of the lock word. * Of particular interest to this code is the test for the * simple case - which we handle inline. For monitor enter, the * simple case is thin lock, held by no-one. For monitor exit, * the simple case is thin lock, held by the unlocking thread with * a recurse count of 0. * * A minor complication is that there is a field in the lock word * unrelated to locking: the hash state. This field must be ignored, but * preserved. * */ static void genMonitorEnter(CompilationUnit *cUnit, MIR *mir) { RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); bool enter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER); ArmLIR *target; ArmLIR *hopTarget; ArmLIR *branch; ArmLIR *hopBranch; assert(LW_SHAPE_THIN == 0); loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj dvmCompilerLockAllTemps(cUnit); // Prepare for explicit register usage dvmCompilerFreeTemp(cUnit, r4PC); // Free up r4 for general use loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0); // Get self genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL); loadWordDisp(cUnit, r0, offsetof(Thread, threadId), r3); // Get threadId newLIR3(cUnit, kThumb2Ldrex, r2, r1, offsetof(Object, lock) >> 2); // Get object->lock opRegImm(cUnit, kOpLsl, r3, LW_LOCK_OWNER_SHIFT); // Align owner // Is lock unheld on lock or held by us (==threadId) on unlock? newLIR4(cUnit, kThumb2Bfi, r3, r2, 0, LW_LOCK_OWNER_SHIFT - 1); newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1); hopBranch = newLIR2(cUnit, kThumb2Cbnz, r2, 0); newLIR4(cUnit, kThumb2Strex, r2, r3, r1, offsetof(Object, lock) >> 2); branch = newLIR2(cUnit, kThumb2Cbz, r2, 0); hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel); hopTarget->defMask = ENCODE_ALL; hopBranch->generic.target = (LIR *)hopTarget; // Clear the lock ArmLIR *inst = newLIR0(cUnit, kThumb2Clrex); // ...and make it a scheduling barrier inst->defMask = ENCODE_ALL; // Export PC (part 1) loadConstant(cUnit, r3, (int) (cUnit->method->insns + mir->offset)); /* Get dPC of next insn */ loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset + dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_ENTER))); // Export PC (part 2) newLIR3(cUnit, kThumb2StrRRI8Predec, r3, rFP, sizeof(StackSaveArea) - offsetof(StackSaveArea, xtra.currentPc)); /* Call template, and don't return */ genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER); // Resume here target = newLIR0(cUnit, kArmPseudoTargetLabel); target->defMask = ENCODE_ALL; branch->generic.target = (LIR *)target; }
/* * Bail to the interpreter. Will not return to this trace. * On entry, rPC must be set correctly. */ static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset) { dvmCompilerFlushAllRegs(cUnit); loadConstant(cUnit, rPC, (int)(cUnit->method->insns + offset)); loadWordDisp(cUnit, rEBP, 0, rECX); // Get glue loadWordDisp(cUnit, rECX, offsetof(Thread, jitToInterpEntries.dvmJitToInterpPunt), rEAX); opReg(cUnit, kOpUncondBr, rEAX); }
/* Export the Dalvik PC assicated with an instruction to the StackSave area */ static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir) { ArmLIR *res; int offset = offsetof(StackSaveArea, xtra.currentPc); int rDPC = dvmCompilerAllocTemp(cUnit); res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset)); newLIR3(cUnit, kThumb2StrRRI8Predec, rDPC, r5FP, sizeof(StackSaveArea) - offset); dvmCompilerFreeTemp(cUnit, rDPC); return res; }
/* Export the Dalvik PC assicated with an instruction to the StackSave area */ static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir) { ArmLIR *res; int rDPC = dvmCompilerAllocTemp(cUnit); int rAddr = dvmCompilerAllocTemp(cUnit); int offset = offsetof(StackSaveArea, xtra.currentPc); res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset)); newLIR2(cUnit, kThumbMovRR, rAddr, rFP); newLIR2(cUnit, kThumbSubRI8, rAddr, sizeof(StackSaveArea) - offset); storeWordDisp( cUnit, rAddr, 0, rDPC); return res; }
static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir) { int offset = offsetof(InterpState, retval); RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg; int signMask = dvmCompilerAllocTemp(cUnit); loadConstant(cUnit, signMask, 0x7fffffff); newLIR2(cUnit, kThumbAndRR, reg0, signMask); dvmCompilerFreeTemp(cUnit, signMask); storeWordDisp(cUnit, rGLUE, offset, reg0); //TUNING: rewrite this to not clobber dvmCompilerClobber(cUnit, reg0); return true; }
TR::Register *OMR::Power::Linkage::pushIntegerWordArg(TR::Node *child) { TR::Register *pushRegister = NULL; TR_ASSERT(child->getDataType() != TR::Address, "assumption violated"); if (child->getRegister() == NULL && child->getOpCode().isLoadConst()) { pushRegister = self()->cg()->allocateRegister(); loadConstant(self()->cg(), child, (int32_t)child->get64bitIntegralValue(), pushRegister); child->setRegister(pushRegister); } else { pushRegister = self()->cg()->evaluate(child); } self()->cg()->decReferenceCount(child); return pushRegister; }
static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir) { int offset = offsetof(Thread, interpSave.retval); RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg); int reglo = regSrc.lowReg; int reghi = regSrc.highReg; int signMask = dvmCompilerAllocTemp(cUnit); loadConstant(cUnit, signMask, 0x7fffffff); storeWordDisp(cUnit, r6SELF, offset, reglo); newLIR2(cUnit, kThumbAndRR, reghi, signMask); dvmCompilerFreeTemp(cUnit, signMask); storeWordDisp(cUnit, r6SELF, offset + 4, reghi); //TUNING: rewrite this to not clobber dvmCompilerClobber(cUnit, reghi); return false; }
/* * Jump to the out-of-line handler in ARM mode to finish executing the * remaining of more complex instructions. */ static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode) { #if USE_IN_CACHE_HANDLER /* * NOTE - In practice BLX only needs one operand, but since the assembler * may abort itself and retry due to other out-of-range conditions we * cannot really use operand[0] to store the absolute target address since * it may get clobbered by the final relative offset. Therefore, * we fake BLX_1 is a two operand instruction and the absolute target * address is stored in operand[1]. */ newLIR2(cUnit, THUMB_BLX_1, (int) gDvmJit.codeCache + templateEntryOffsets[opCode], (int) gDvmJit.codeCache + templateEntryOffsets[opCode]); newLIR2(cUnit, THUMB_BLX_2, (int) gDvmJit.codeCache + templateEntryOffsets[opCode], (int) gDvmJit.codeCache + templateEntryOffsets[opCode]); #else /* * In case we want to access the statically compiled handlers for * debugging purposes, define USE_IN_CACHE_HANDLER to 0 */ void *templatePtr; #define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X(); #include "../../../template/armv5te-vfp/TemplateOpList.h" #undef JIT_TEMPLATE switch (opCode) { #define JIT_TEMPLATE(X) \ case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; } #include "../../../template/armv5te-vfp/TemplateOpList.h" #undef JIT_TEMPLATE default: templatePtr = NULL; } loadConstant(cUnit, r7, (int) templatePtr); newLIR1(cUnit, THUMB_BLX_R, r7); #endif }
/* * Jump to the out-of-line handler to finish executing the * remaining of more complex instructions. */ static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpcode opCode) { /* * We're jumping from a trace to a template. Using jal is preferable to jalr, * but we need to ensure source and target addresses allow the use of jal. * This should almost always be the case, but if source and target are in * different 256mb regions then use jalr. The test below is very conservative * since we don't have a source address yet, but this is ok for now given that * we expect this case to be very rare. The test can be made less conservative * as needed in the future in coordination with address assignment during * the assembly process. */ dvmCompilerClobberHandlerRegs(cUnit); int targetAddr = (int) gDvmJit.codeCache + templateEntryOffsets[opCode]; int maxSourceAddr = (int) gDvmJit.codeCache + gDvmJit.codeCacheSize; if ((targetAddr & 0xF0000000) == (maxSourceAddr & 0xF0000000)) { newLIR1(cUnit, kMipsJal, targetAddr); } else { loadConstant(cUnit, r_T9, targetAddr); newLIR2(cUnit, kMipsJalr, r_RA, r_T9); } }
void GPUProgram::setArgs(RenderDevice* renderDevice, const ArgList& args) { int numVariables = 0; // Iterate through formal bindings for (int b = 0; b < bindingTable.bindingArray.size(); ++b) { const BindingTable::Binding& binding = bindingTable.bindingArray[b]; if (binding.source == VARIABLE) { ++numVariables; alwaysAssertM(args.argTable.containsKey(binding.name), std::string("No value provided for GPUProgram variable \"") + binding.name + "\""); const ArgList::Arg& arg = args.argTable[binding.name]; // check the type alwaysAssertM(arg.type == binding.type, std::string("Variable \"") + binding.name + "\" was declared as type " + GPUProgram::toString(binding.type) + " and the values supplied" + " at runtime had type " + GPUProgram::toString(arg.type)); if (binding.slot != BindingTable::Binding::UNASSIGNED) { switch (binding.type) { case SAMPLER1D: case SAMPLER2D: case SAMPLER3D: case SAMPLERCUBE: case SAMPLERRECT: renderDevice->setTexture(binding.slot, arg.texture); break; case FLOAT4: case FLOAT3: case FLOAT2: case FLOAT1: loadConstant(binding.slot, arg.vector[0]); break; case FLOAT2X2: alwaysAssertM(false, "FLOAT2X2 not implemented."); break; case FLOAT3X3: for (int s = 0; s < 3; ++s) { loadConstant(binding.slot + s, arg.vector[s]); } break; case FLOAT4X4: for (int s = 0; s < 4; ++s) { loadConstant(binding.slot + s, arg.vector[s]); } break; } } } } if (numVariables < args.argTable.size()) { // Some variables were unused. Figure out which they were. Table<std::string, ArgList::Arg>::Iterator arg = args.argTable.begin(); Table<std::string, ArgList::Arg>::Iterator end = args.argTable.end(); while (arg != end) { // See if this arg was in the formal binding list bool foundArgument = false; for (int b = 0; b < bindingTable.bindingArray.size(); ++b) { if (bindingTable.bindingArray[b].name == arg->key) { foundArgument = true; break; } } debugAssertM(foundArgument, std::string("Unused GPU program argument specified: \"") + arg->key + "\"."); ++arg; } } }
// operand count((operand0 flags, operand0 operator index, operand0 result index)...(operand0 flags, [operandN operator index, operandN result index|operandN constant value])) // alternate operand specification: // (operand0 flags, constant count(constant0 value,...,constantN value)) bool ATKIOperator::load(Stream *program) { if (!loadProperties(program)) { program->flush(); return false; } char buffer[21]; memset(buffer, 0, 21); int index = 0; bool valid = false; while(Antikythera::readProgram(program)) { char c = (char)program->read(); program->print(c); if (c == '(') { valid = true; break; } if (index == 3) { #ifdef ANTIKYTHERA_DEBUG m_lastErrorString = m_name + "::load() - operand count has too many digits."; #endif program->flush(); return false; } if (!isdigit(c)) { #ifdef ANTIKYTHERA_DEBUG m_lastErrorString = m_name + "::load() - operand count contains invalid character: " + String(c); #endif program->flush(); return false; } buffer[index++] = c; } if (!valid) { #ifdef ANTIKYTHERA_DEBUG m_lastErrorString = m_name + "::load() - unexpected end of stream while reading operand count."; #endif program->flush(); return false; } initializeOperands((uint8_t)strtoul(buffer, NULL, 10)); #ifdef ANTIKYTHERA_DEBUG program->print("[num operands:"); program->print(buffer); program->println("]"); #endif for (int count = 0; count < m_numOperands; count++) { valid = false; while(Antikythera::readProgram(program)) { char c = (char)program->read(); program->print(c); if (c == '(') { valid = true; break; } #ifdef ANTIKYTHERA_DEBUG m_lastErrorString = m_name + "::load() - operand[" + String(count) + "] expected opening parenthesis, read invalid character: " + String(c); #endif program->flush(); return false; } if (!valid) { #ifdef ANTIKYTHERA_DEBUG m_lastErrorString = m_name + "::load() - operand[" + String(count) + "] unexpected end of stream while reading opening parenthesis."; #endif program->flush(); return false; } if (!loadFlags(program, &m_operands[count].flags)) { return false; } if (m_operands[count].flags & OPERANDFLAG_LINK) { if (!loadOperatorIndex(program, &m_operands[count].operatorIndex)) { return false; } if (!loadResultIndex(program, &m_operands[count].resultIndex)) { return false; } } else { if (!loadConstant(program, count, m_operands[count].flags)) { return false; } valid = false; while(Antikythera::readProgram(program)) { char c = (char)program->read(); program->print(c); if (c == ')') { valid = true; break; } #ifdef ANTIKYTHERA_DEBUG m_lastErrorString = m_name + "::load() - expected closing parenthesis, read invalid character: " + String(c); #endif program->flush(); return false; } if (!valid) { #ifdef ANTIKYTHERA_DEBUG m_lastErrorString = m_name + "::load() - unexpected end of stream while reading closing parenthesis."; #endif program->flush(); return false; } } } valid = false; while(Antikythera::readProgram(program)) { char c = (char)program->read(); program->print(c); if (c == ')') { valid = true; break; } #ifdef ANTIKYTHERA_DEBUG m_lastErrorString = m_name + "::load() - expected closing parenthesis, read invalid character: " + String(c); #endif program->flush(); return false; } if (!valid) { #ifdef ANTIKYTHERA_DEBUG m_lastErrorString = m_name + "::load() - unexpected end of stream while reading closing parenthesis."; #endif program->flush(); return false; } // connect root to leaf nodes return true; }
MainWindow::MainWindow(QDesktopWidget * d):QMainWindow() { this->setMinimumSize(d->availableGeometry().width()/1.15, d->availableGeometry().height()/1.25); this->setDockNestingEnabled(false); this->setDockOptions(NULL); this->setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); this->setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); this->setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); this->setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); databackend=new DataBackend(); databackend->setDataInserter(new ChangeFactory(databackend)); databrowser=new DataBrowser(databackend,d); dataeditor=new DataEditor(databackend,d); QObject::connect(databrowser,SIGNAL(editObject(QString)),dataeditor,SLOT(loadObject(QString))); QObject::connect(databrowser,SIGNAL(editForce(QString)),dataeditor,SLOT(loadForce(QString))); QObject::connect(databrowser,SIGNAL(editMacro(QString)),dataeditor,SLOT(loadMacro(QString))); QObject::connect(databrowser,SIGNAL(editConstant(QString)),dataeditor,SLOT(loadConstant(QString))); QObject::connect(databrowser,SIGNAL(deleteObject(QString)),dataeditor,SLOT(loadBlank())); QObject::connect(databrowser,SIGNAL(deleteForce(QString)),dataeditor,SLOT(loadBlank())); QObject::connect(databrowser,SIGNAL(deleteMacro(QString)),dataeditor,SLOT(loadBlank())); QObject::connect(databrowser,SIGNAL(deleteConstant(QString)),dataeditor,SLOT(loadBlank())); simcontrol=new SimulationControl(databackend); openglpane=new GLDrawPane(databackend,d); timer = new QTimer(this); connect(timer, SIGNAL(timeout()), openglpane, SLOT(updateGL())); connect(qApp, SIGNAL(lastWindowClosed()),timer,SLOT(stop())); timer -> start(15); this->setCentralWidget(openglpane); this->addDockWidget(Qt::RightDockWidgetArea, databrowser); this->addDockWidget(Qt::RightDockWidgetArea, dataeditor); this->addDockWidget(Qt::BottomDockWidgetArea, simcontrol); QMenu * fileMenu = this->menuBar()->addMenu(tr("File")); QMenu * newMenu=fileMenu->addMenu("New Project"); newMenu->addAction("Blank Project",databackend,SLOT(newFromBlank()),QKeySequence("Ctrl+N")); newMenu->addAction("From Default",databackend,SLOT(newFromDefault()),QKeySequence("Ctrl+Shift+N")); fileMenu->addAction("Open Project",databackend,SLOT(load()),QKeySequence("Ctrl+O")); fileMenu->addAction("Save Project",databackend,SLOT(save()),QKeySequence("Ctrl+S")); fileMenu->addAction("Save Project As",databackend,SLOT(saveAs()),QKeySequence("Ctrl+Shift+S")); fileMenu->addAction("Exit",databackend, SLOT(quit())); QMenu * editMenu = this->menuBar()->addMenu(tr("Edit")); QAction * undo=databackend->getUndoStack()->createUndoAction(this); undo->setShortcut(QKeySequence(QKeySequence::Undo)); editMenu->addAction(undo); QAction * redo=databackend->getUndoStack()->createRedoAction(this); redo->setShortcut(QKeySequence(QKeySequence::Redo)); editMenu->addAction(redo); QMenu * viewMenu = this->menuBar()->addMenu(tr("View")); QMenu * cameraMenu=viewMenu->addMenu("Camera Presets"); cameraMenu->addAction("Isometric",this,SLOT(view_setIsometric())); cameraMenu->addAction("View XY Plane",this,SLOT(view_setXY())); cameraMenu->addAction("View XZ Plane",this,SLOT(view_setXZ())); cameraMenu->addAction("View YZ Plane",this,SLOT(view_setYZ())); QMenu * zoomMenu=viewMenu->addMenu("Zoom"); QActionGroup * zoomGroup=new QActionGroup(NULL); zoomGroup->addAction(zoomMenu->addAction("10%",this,SLOT(view_zoom10())))->setCheckable(true); zoomGroup->addAction(zoomMenu->addAction("50%",this,SLOT(view_zoom50())))->setCheckable(true); zoomGroup->addAction(zoomMenu->addAction("100%",this,SLOT(view_zoom100())))->setCheckable(true); zoomGroup->addAction(zoomMenu->addAction("150%",this,SLOT(view_zoom150())))->setCheckable(true); zoomGroup->addAction(zoomMenu->addAction("200%",this,SLOT(view_zoom200())))->setCheckable(true); view_zoom50(); viewMenu->addSeparator(); viewMenu->addAction(databrowser->toggleViewAction()); viewMenu->addAction(dataeditor->toggleViewAction()); viewMenu->addAction(simcontrol->toggleViewAction()); QMenu * simulationMenu = this->menuBar()->addMenu(tr("Simulation")); simulationMenu->addAction("Run",simcontrol->getStepEngine(),SLOT(startPull()),QKeySequence("Ctrl+R")); simulationMenu->addAction("Pause",simcontrol->getStepEngine(),SLOT(stopPull()),QKeySequence("Ctrl+P")); simulationMenu->addAction("Reset to Initial Conditions",databackend->getUndoStack(),SLOT(undo()),QKeySequence("Ctrl+Shift+R")); QAction * a=simulationMenu->addAction("Warn Before Clearing Undo Stack"); a->setCheckable(true); a->setChecked(true); QObject::connect(a,SIGNAL(toggled(bool)),databackend,SLOT(setWarning(bool))); QMenu * dataMenu = this->menuBar()->addMenu(tr("Data")); dataMenu->addAction("Clear All Objects",databackend->getDataInserter(),SLOT(clearObjects())); dataMenu->addAction("Clear All Forces",databackend->getDataInserter(),SLOT(clearForces())); dataMenu->addAction("Clear All Macros",databackend->getDataInserter(),SLOT(clearMacros())); dataMenu->addAction("Clear All Constants",databackend->getDataInserter(),SLOT(clearConstants())); QMenu * helpMenu = this->menuBar()->addMenu(tr("Help")); helpMenu->addAction("Manual",this,SLOT(showManual())); helpMenu->addAction("About",this,SLOT(showAbout())); }