void Opcode::Enter(Context *context) // ---------------------------------------------------------------------------- // Enter all the opcodes declared using the macros // ---------------------------------------------------------------------------- { for (Opcodes::iterator o = opcodes->begin(); o != opcodes->end(); o++) { Opcode *opcode = *o; opcode->Register(context); } }
/* * Turns a VMMethod into a C++ vector of Opcodes. */ std::vector<Opcode*> VMMethod::create_opcodes() { std::vector<Opcode*> ops; std::map<int, size_t> stream2opcode; VMMethod::Iterator iter(this); /* Fill +ops+ with all our Opcode objects, maintain * the map from stream position to instruction. */ for(size_t ipos = 0; !iter.end(); ipos++, iter.inc()) { stream2opcode[iter.position] = ipos; Opcode* lop = new Opcode(iter); ops.push_back(lop); } /* Iterate through the ops, fixing goto locations to point * to opcodes and set start_block on any opcode that is * the beginning of a block */ bool next_new = false; for(std::vector<Opcode*>::iterator i = ops.begin(); i != ops.end(); i++) { Opcode* op = *i; if(next_new) { op->start_block = true; next_new = false; } /* We patch and mark where we branch to. */ if(op->is_goto()) { op->arg1 = stream2opcode[op->arg1]; ops.at(op->arg1)->start_block = true; } /* This terminates the block. */ if(op->is_terminator()) { /* this ends a block. */ next_new = true; } } // TODO take the exception table into account here /* Go through again and assign each opcode a block * number. */ size_t block = 0; for(std::vector<Opcode*>::iterator i = ops.begin(); i != ops.end(); i++) { Opcode* op = *i; if(op->start_block) block++; op->block = block; } return ops; }
Opcode * Opcode::Find(Tree *self, text name) // ---------------------------------------------------------------------------- // Find an opcode that matches the name if there is one // ---------------------------------------------------------------------------- { for (Opcodes::iterator o = opcodes->begin(); o != opcodes->end(); o++) { Opcode *opcode = *o; if (opcode->OpID() == name) return opcode; } Ooops("Invalid opcode name in $1", self); return NULL; }
/// Verify that the given symbol (written by the given op) is legal to /// be written. void OSLCompilerImpl::check_write_legality (const Opcode &op, int opnum, const Symbol *sym) { // We can never write to constant symbols if (sym->symtype() == SymTypeConst) { error (op.sourcefile(), op.sourceline(), "Attempted to write to a constant value"); } // Params can only write if it's part of their initialization if (sym->symtype() == SymTypeParam && (opnum < sym->initbegin() || opnum >= sym->initend())) { error (op.sourcefile(), op.sourceline(), "Cannot write to input parameter '%s' (op %d)", sym->name().c_str(), opnum); } // FIXME -- check for writing to globals. But it's tricky, depends on // what kind of shader we are. }
void RuntimeOptimizer::llvm_generate_debugnan (const Opcode &op) { for (int i = 0; i < op.nargs(); ++i) { Symbol &sym (*opargsym (op, i)); if (! op.argwrite(i)) continue; TypeDesc t = sym.typespec().simpletype(); if (t.basetype != TypeDesc::FLOAT) continue; // just check float-based types int ncomps = t.numelements() * t.aggregate; llvm::Value *args[] = { llvm_constant(ncomps), llvm_void_ptr(sym), llvm_constant((int)sym.has_derivs()), sg_void_ptr(), llvm_constant(op.sourcefile()), llvm_constant(op.sourceline()), llvm_constant(sym.name()) }; llvm_call_function ("osl_naninf_check", args, 7); } }
void BackendLLVM::llvm_generate_debug_uninit (const Opcode &op) { for (int i = 0; i < op.nargs(); ++i) { Symbol &sym (*opargsym (op, i)); if (! op.argread(i)) continue; if (sym.typespec().is_closure_based()) continue; TypeDesc t = sym.typespec().simpletype(); if (t.basetype != TypeDesc::FLOAT && t.basetype != TypeDesc::INT && t.basetype != TypeDesc::STRING) continue; // just check float, int, string based types llvm::Value *ncheck = ll.constant (int(t.numelements() * t.aggregate)); llvm::Value *offset = ll.constant(0); // Some special cases... if (op.opname() == Strings::op_for && i == 0) { // The first argument of 'for' is the condition temp, but // note that it may not have had its initializer run yet, so // don't generate uninit test code for it. continue; } if (op.opname() == op_aref && i == 1) { // Special case -- array assignment -- only check one element llvm::Value *ind = llvm_load_value (*opargsym (op, 2)); llvm::Value *agg = ll.constant(t.aggregate); offset = t.aggregate == 1 ? ind : ll.op_mul (ind, agg); ncheck = agg; } else if (op.opname() == op_compref && i == 1) { // Special case -- component assignment -- only check one channel llvm::Value *ind = llvm_load_value (*opargsym (op, 2)); offset = ind; ncheck = ll.constant(1); } llvm::Value *args[] = { ll.constant(t), llvm_void_ptr(sym), sg_void_ptr(), ll.constant(op.sourcefile()), ll.constant(op.sourceline()), ll.constant(sym.name()), offset, ncheck }; ll.call_function ("osl_uninit_check", args, 8); } }
void BackendLLVM::llvm_generate_debugnan (const Opcode &op) { for (int i = 0; i < op.nargs(); ++i) { Symbol &sym (*opargsym (op, i)); if (! op.argwrite(i)) continue; TypeDesc t = sym.typespec().simpletype(); if (t.basetype != TypeDesc::FLOAT) continue; // just check float-based types llvm::Value *ncomps = ll.constant (int(t.numelements() * t.aggregate)); llvm::Value *offset = ll.constant(0); llvm::Value *ncheck = ncomps; if (op.opname() == op_aassign) { // Special case -- array assignment -- only check one element ASSERT (i == 0 && "only arg 0 is written for aassign"); llvm::Value *ind = llvm_load_value (*opargsym (op, 1)); llvm::Value *agg = ll.constant(t.aggregate); offset = t.aggregate == 1 ? ind : ll.op_mul (ind, agg); ncheck = agg; } else if (op.opname() == op_compassign) { // Special case -- component assignment -- only check one channel ASSERT (i == 0 && "only arg 0 is written for compassign"); llvm::Value *ind = llvm_load_value (*opargsym (op, 1)); offset = ind; ncheck = ll.constant(1); } llvm::Value *args[] = { ncomps, llvm_void_ptr(sym), ll.constant((int)sym.has_derivs()), sg_void_ptr(), ll.constant(op.sourcefile()), ll.constant(op.sourceline()), ll.constant(sym.name()), offset, ncheck, ll.constant(op.opname()) }; ll.call_function ("osl_naninf_check", args, 10); } }
IntermediateData *ScriptParser::generateOCode(FunctionData *fdata) { //Z_message("yes"); bool failure = false; vector<ASTFuncDecl *> funcs = fdata->functions; vector<ASTVarDecl *> globals = fdata->globalVars; vector<ASTArrayDecl *> globalas = fdata->globalArrays; //we have no need of newglobals at this point anymore for(vector<ASTVarDecl *>::iterator it = fdata->newGlobalVars.begin(); it != fdata->newGlobalVars.end(); it++) globals.push_back(*it); for(vector<ASTArrayDecl *>::iterator it = fdata->newGlobalArrays.begin(); it != fdata->newGlobalArrays.end(); it++) globalas.push_back(*it); map<string, int> runsymbols = fdata->scriptRunSymbols; SymbolTable *symbols = fdata->symbols; map<string, int> numparams = fdata->numParams; map<string, int> scripttypes = fdata->scriptTypes; map<string, int> thisptr = fdata->thisPtr; delete fdata; LinkTable lt; for(vector<ASTVarDecl *>::iterator it = globals.begin(); it != globals.end(); it++) { int vid2 = symbols->getID(*it); lt.addGlobalVar(vid2); } for(vector<ASTArrayDecl *>::iterator it = globalas.begin(); it != globalas.end(); it++) { int vid2 = symbols->getID(*it); lt.addGlobalVar(vid2); } //Z_message("yes"); //and add the this pointers for(vector<int>::iterator it = symbols->getGlobalPointers().begin(); it != symbols->getGlobalPointers().end(); it++) { lt.addGlobalPointer(*it); } for(vector<ASTFuncDecl *>::iterator it = funcs.begin(); it != funcs.end(); it++) { int fid2 = symbols->getID(*it); lt.functionToLabel(fid2); } //Z_message("yes"); //we now have labels for the functions and ids for the global variables. //we can now generate the code to intialize the globals IntermediateData *rval = new IntermediateData(); //Link against the global symbols, and add their labels map<int, vector<Opcode *> > globalcode = GlobalSymbols::getInst().addSymbolsCode(lt); for(map<int, vector<Opcode *> >::iterator it = globalcode.begin(); it != globalcode.end(); it++) { rval->funcs[it->first] = it->second; } globalcode = FFCSymbols::getInst().addSymbolsCode(lt); for(map<int, vector<Opcode *> >::iterator it = globalcode.begin(); it != globalcode.end(); it++) { rval->funcs[it->first] = it->second; } globalcode = ItemSymbols::getInst().addSymbolsCode(lt); for(map<int, vector<Opcode *> >::iterator it = globalcode.begin(); it != globalcode.end(); it++) { rval->funcs[it->first] = it->second; } globalcode = ItemclassSymbols::getInst().addSymbolsCode(lt); for(map<int, vector<Opcode *> >::iterator it = globalcode.begin(); it != globalcode.end(); it++) { rval->funcs[it->first] = it->second; } globalcode = LinkSymbols::getInst().addSymbolsCode(lt); for(map<int, vector<Opcode *> >::iterator it = globalcode.begin(); it != globalcode.end(); it++) { rval->funcs[it->first] = it->second; } globalcode = ScreenSymbols::getInst().addSymbolsCode(lt); for(map<int, vector<Opcode *> >::iterator it = globalcode.begin(); it != globalcode.end(); it++) { rval->funcs[it->first] = it->second; } globalcode = GameSymbols::getInst().addSymbolsCode(lt); for(map<int, vector<Opcode *> >::iterator it = globalcode.begin(); it != globalcode.end(); it++) { rval->funcs[it->first] = it->second; } globalcode = NPCSymbols::getInst().addSymbolsCode(lt); for(map<int, vector<Opcode *> >::iterator it = globalcode.begin(); it != globalcode.end(); it++) { rval->funcs[it->first] = it->second; } globalcode = LinkWeaponSymbols::getInst().addSymbolsCode(lt); for(map<int, vector<Opcode *> >::iterator it = globalcode.begin(); it != globalcode.end(); it++) { rval->funcs[it->first] = it->second; } globalcode = EnemyWeaponSymbols::getInst().addSymbolsCode(lt); for(map<int, vector<Opcode *> >::iterator it = globalcode.begin(); it != globalcode.end(); it++) { rval->funcs[it->first] = it->second; } //Z_message("yes"); for(vector<ASTVarDecl *>::iterator it = globals.begin(); it != globals.end(); it++) { OpcodeContext oc; oc.linktable = < oc.symbols = symbols; oc.stackframe = NULL; BuildOpcodes bo; (*it)->execute(bo, &oc); if(!bo.isOK()) { failure = true; } vector<Opcode *> code = bo.getResult(); for(vector<Opcode *>::iterator it2 = code.begin(); it2!= code.end(); it2++) { rval->globalsInit.push_back(*it2); } delete *it; //say so long to our lovely data structure the AST } //Z_message("yes"); for(vector<ASTArrayDecl *>::iterator it = globalas.begin(); it != globalas.end(); it++) { OpcodeContext oc; oc.linktable = < oc.symbols = symbols; oc.stackframe = NULL; BuildOpcodes bo; (*it)->execute(bo, &oc); if(!bo.isOK()) { failure = true; } vector<Opcode *> code = bo.getResult(); for(vector<Opcode *>::iterator it2 = code.begin(); it2!= code.end(); it2++) { rval->globalasInit.push_back(*it2); } delete *it; //say so long to our lovely data structure the AST } //Z_message("yes"); //globals have been initialized, now we repeat for the functions for(vector<ASTFuncDecl *>::iterator it = funcs.begin(); it != funcs.end(); it++) { bool isarun = false; string scriptname; for(map<string,int>::iterator it2 = runsymbols.begin(); it2 != runsymbols.end(); it2++) { if(it2->second == symbols->getID(*it)) { isarun=true; scriptname = it2->first; break; } } vector<Opcode *> funccode; //count the number of stack-allocated variables vector<int> stackvars; pair<vector<int> *, SymbolTable *> param = pair<vector<int> *, SymbolTable *>(&stackvars, symbols); CountStackSymbols temp; (*it)->execute(temp, ¶m); int offset = 0; StackFrame sf; //if this is a run, there is the this pointer if(isarun) { sf.addToFrame(thisptr[scriptname], offset); offset += 10000; } //the params are now the first elements of this list //so assign them depths in reverse order for(vector<int>::reverse_iterator it2 = stackvars.rbegin(); it2 != stackvars.rend(); it2++) { sf.addToFrame(*it2, offset); offset += 10000; } //start of the function Opcode *first = new OSetImmediate(new VarArgument(EXP1), new LiteralArgument(0)); first->setLabel(lt.functionToLabel(symbols->getID(*it))); funccode.push_back(first); //push on the 0s int numtoallocate = (unsigned int)stackvars.size()-(unsigned int)symbols->getFuncParams(symbols->getID(*it)).size(); for(int i = 0; i < numtoallocate; i++) { funccode.push_back(new OPushRegister(new VarArgument(EXP1))); } //push on the this, if a script if(isarun) { switch(scripttypes[scriptname]) { case ScriptParser::TYPE_FFC: funccode.push_back(new OSetRegister(new VarArgument(EXP2), new VarArgument(REFFFC))); break; case ScriptParser::TYPE_ITEMCLASS: funccode.push_back(new OSetRegister(new VarArgument(EXP2), new VarArgument(REFITEMCLASS))); break; case ScriptParser::TYPE_GLOBAL: //don't care, we don't have a valid this pointer break; } funccode.push_back(new OPushRegister(new VarArgument(EXP2))); } //set up the stack frame register funccode.push_back(new OSetRegister(new VarArgument(SFRAME), new VarArgument(SP))); OpcodeContext oc; oc.linktable = < oc.symbols = symbols; oc.stackframe = &sf; BuildOpcodes bo; (*it)->execute(bo, &oc); if(!bo.isOK()) failure = true; vector<Opcode *> code = bo.getResult(); for(vector<Opcode *>::iterator it2 = code.begin(); it2 != code.end(); it2++) { funccode.push_back(*it2); } //add appendix code //nop label Opcode *next = new OSetImmediate(new VarArgument(EXP2), new LiteralArgument(0)); next->setLabel(bo.getReturnLabelID()); funccode.push_back(next); //pop off everything for(unsigned int i=0; i< stackvars.size(); i++) { funccode.push_back(new OPopRegister(new VarArgument(EXP2))); } //if it's a main script, quit. if(isarun) funccode.push_back(new OQuit()); else { //pop off the return address funccode.push_back(new OPopRegister(new VarArgument(EXP2))); //and return funccode.push_back(new OGotoRegister(new VarArgument(EXP2))); } rval->funcs[lt.functionToLabel(symbols->getID(*it))]=funccode; delete *it; } //Z_message("yes"); //update the run symbols for(map<string, int>::iterator it = runsymbols.begin(); it != runsymbols.end(); it++) { int labelid = lt.functionToLabel(it->second); rval->scriptRunLabels[it->first] = labelid; rval->numParams[it->first] = numparams[it->first]; rval->scriptTypes[it->first] = scripttypes[it->first]; } delete symbols; //and so long to our beloved ;) symbol table //Z_message("yes"); if(failure) { //delete all kinds of crap if there was a problem :-/ for(map<int, vector<Opcode *> >::iterator it = rval->funcs.begin(); it != rval->funcs.end(); it++) { for(vector<Opcode *>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++) { delete *it2; } } for(vector<Opcode *>::iterator it = rval->globalsInit.begin(); it != rval->globalsInit.end(); it++) { delete *it; } for(vector<Opcode *>::iterator it = rval->globalasInit.begin(); it != rval->globalasInit.end(); it++) { delete *it; } delete rval; return NULL; } //Z_message("yes"); return rval; }
IntermediateData* ScriptParser::generateOCode(FunctionData& fdata) { Program& program = fdata.program; TypeStore& typeStore = program.getTypeStore(); vector<Datum*>& globalVariables = fdata.globalVariables; // Z_message("yes"); bool failure = false; //we now have labels for the functions and ids for the global variables. //we can now generate the code to intialize the globals IntermediateData *rval = new IntermediateData(fdata); // Push 0s for init stack space. rval->globalsInit.push_back( new OSetImmediate(new VarArgument(EXP1), new LiteralArgument(0))); int globalStackSize = *program.getScope().getRootStackSize(); for (int i = 0; i < globalStackSize; ++i) rval->globalsInit.push_back( new OPushRegister(new VarArgument(EXP1))); // Generate variable init code. for (vector<Datum*>::iterator it = globalVariables.begin(); it != globalVariables.end(); ++it) { Datum& variable = **it; AST& node = *variable.getNode(); OpcodeContext oc; oc.typeStore = &typeStore; BuildOpcodes bo(typeStore); node.execute(bo, &oc); if (bo.hasFailed()) failure = true; appendElements(rval->globalsInit, oc.initCode); appendElements(rval->globalsInit, bo.getResult()); } // Pop off everything. for (int i = 0; i < globalStackSize; ++i) rval->globalsInit.push_back( new OPopRegister(new VarArgument(EXP2))); //globals have been initialized, now we repeat for the functions vector<Function*> funs = program.getUserFunctions(); for (vector<Function*>::iterator it = funs.begin(); it != funs.end(); ++it) { Function& function = **it; ASTFuncDecl& node = *function.node; bool isRun = ZScript::isRun(function); string scriptname; Script* functionScript = function.getScript(); if (functionScript) scriptname = functionScript->getName(); vector<Opcode *> funccode; int stackSize = getStackSize(function); // Start of the function. Opcode* first = new OSetImmediate(new VarArgument(EXP1), new LiteralArgument(0)); first->setLabel(function.getLabel()); funccode.push_back(first); // Push 0s for the local variables. for (int i = stackSize - getParameterCount(function); i > 0; --i) funccode.push_back(new OPushRegister(new VarArgument(EXP1))); // Push on the this, if a script if (isRun) { ScriptType type = program.getScript(scriptname)->getType(); if (type == ScriptType::getFfc()) funccode.push_back( new OSetRegister(new VarArgument(EXP2), new VarArgument(REFFFC))); else if (type == ScriptType::getItem()) funccode.push_back( new OSetRegister(new VarArgument(EXP2), new VarArgument(REFITEMCLASS))); funccode.push_back(new OPushRegister(new VarArgument(EXP2))); } // Set up the stack frame register funccode.push_back(new OSetRegister(new VarArgument(SFRAME), new VarArgument(SP))); OpcodeContext oc; oc.typeStore = &typeStore; BuildOpcodes bo(typeStore); node.execute(bo, &oc); if (bo.hasFailed()) failure = true; appendElements(funccode, bo.getResult()); // Add appendix code. Opcode* next = new OSetImmediate(new VarArgument(EXP2), new LiteralArgument(0)); next->setLabel(bo.getReturnLabelID()); funccode.push_back(next); // Pop off everything. for (int i = 0; i < stackSize; ++i) { funccode.push_back(new OPopRegister(new VarArgument(EXP2))); } //if it's a main script, quit. if (isRun) { // Note: the stack still contains the "this" pointer // But since the script is about to terminate, we don't // care about popping it off. funccode.push_back(new OQuit()); } else { // Not a script's run method, so no "this" pointer to // pop off. The top of the stack is now the function // return address (pushed on by the caller). //pop off the return address funccode.push_back(new OPopRegister(new VarArgument(EXP2))); //and return funccode.push_back(new OGotoRegister(new VarArgument(EXP2))); } function.giveCode(funccode); } if (failure) { delete rval; return NULL; } //Z_message("yes"); return rval; }