/******************* FUNCTION *********************/ void ProjectActionOld::genItLoopCCode ( ostream& out, const CMRProjectContext& context, int depth ) const { CMRProjectContext localContext(&context); //errors assert(name == "cmrSubBlock" && description == "cmrIteratorLoop"); //search the related iterator definition const CMRProjectEntity * entity = context.parent->find(eq->latexEntity); if (entity == NULL) { cerr << "Can't find the definition of iterator " << eq->compute << " in current context." << endl; abort(); } const CMRProjectIterator * iterator = dynamic_cast<const CMRProjectIterator*>(entity); if (iterator == NULL) { cerr << "Cuation, expect iterator " << eq->compute << " but get another type." << endl; context.printDebug(); abort(); } assert(iterator != NULL); CMRProjectLocalVariable localVar(eq->compute,eq->compute); localContext.addEntry(&localVar); out << genCCodeIndent(depth) << "for (int " << eq->compute << " = " << iterator->start << " ; " << eq->compute << " < " << iterator->end << " ; " << eq->compute << "++ )" <<endl; out << genCCodeIndent(depth) << "{" << endl; for (ConstIterator it = getFirstChild() ; ! it.isEnd() ; ++it) it->genCCode(out,it->context,depth+1); //it->genCCode(out,localContext,depth+1); out << genCCodeIndent(depth) << "}" << endl; //checkContext(localContext); }
ExprType ExprAssignNode::prep(bool wantScalar, ExprVarEnvBuilder& envBuilder) { _assignedType = child(0)->prep(false, envBuilder); std::unique_ptr<ExprLocalVar> localVar(new ExprLocalVar(child(0)->type())); _localVar = localVar.get(); envBuilder.current()->add(_name, std::move(localVar)); bool error = false; checkCondition( _assignedType.isValid(), std::string("Assignment operation has bad type: ") + _type.toString(), error); if (error) setType(ExprType().Error()); else setTypeWithChildLife(ExprType().None()); return _type; }
std::string Value::toString() const { switch (kind()) { case SELF: return "self"; case THIS: return "this"; case CONSTANT: return makeString("Constant(%s)", constant().toString().c_str()); case ALIAS: return makeString("Alias(alias: %s, templateArguments: %s)", alias().toString().c_str(), makeArrayString(aliasTemplateArguments()).c_str()); case PREDICATE: return makeString("Predicate(%s)", predicate().toString().c_str()); case LOCALVAR: return makeString("LocalVar(%s)", localVar().toString().c_str()); case REINTERPRET: return makeString("Reinterpret(value: %s)", reinterpretOperand().toString().c_str()); case DEREF_REFERENCE: return makeString("DerefReference(%s)", derefOperand().toString().c_str()); case TERNARY: return makeString("Ternary(cond: %s, ifTrue: %s, ifFalse: %s)", ternaryCondition().toString().c_str(), ternaryIfTrue().toString().c_str(), ternaryIfFalse().toString().c_str()); case CAST: return makeString("Cast(value: %s, targetType: %s)", castOperand().toString().c_str(), castTargetType()->toString().c_str()); case POLYCAST: return makeString("PolyCast(value: %s, targetType: %s)", polyCastOperand().toString().c_str(), polyCastTargetType()->toString().c_str()); case INTERNALCONSTRUCT: return makeString("InternalConstruct(args: %s)", makeArrayString(internalConstructParameters()).c_str()); case MEMBERACCESS: return makeString("MemberAccess(object: %s, var: %s)", memberAccessObject().toString().c_str(), memberAccessVar().toString().c_str()); case BIND_REFERENCE: return makeString("BindReference(value: %s)", bindReferenceOperand().toString().c_str()); case TYPEREF: return makeString("TypeRef(targetType: %s)", typeRefType()->toString().c_str()); case TEMPLATEVARREF: return makeString("TemplateVarRef(templateVar: %s)", templateVar()->toString().c_str()); case CALL: return makeString("Call(funcValue: %s, args: %s)", callValue().toString().c_str(), makeArrayString(callParameters()).c_str()); case FUNCTIONREF: return makeString("FunctionRef(name: %s, type: %s, parentType: %s, templateArgs: %s)", functionRefFunction().fullName().toString().c_str(), type()->toString().c_str(), functionRefParentType() != nullptr ? functionRefParentType()->toString().c_str() : "[NONE]", makeArrayString(functionRefTemplateArguments()).c_str()); case TEMPLATEFUNCTIONREF: return makeString("TemplateFunctionRef(name: %s, parentType: %s)", templateFunctionRefName().c_str(), templateFunctionRefParentType()->toString().c_str()); case METHODOBJECT: return makeString("MethodObject(method: %s, object: %s)", methodObject().toString().c_str(), methodOwner().toString().c_str()); case INTERFACEMETHODOBJECT: return makeString("InterfaceMethodObject(method: %s, object: %s)", interfaceMethodObject().toString().c_str(), interfaceMethodOwner().toString().c_str()); case STATICINTERFACEMETHODOBJECT: return makeString("StaticInterfaceMethodObject(method: %s, typeRef: %s)", staticInterfaceMethodObject().toString().c_str(), staticInterfaceMethodOwner().toString().c_str()); case CAPABILITYTEST: return makeString("CapabilityTest(checkType: %s, capabilityType: %s)", capabilityTestCheckType()->toString().c_str(), capabilityTestCapabilityType()->toString().c_str()); case Value::ARRAYLITERAL: return makeString("ArrayLiteral(type: %s, values: %s)", type()->toString().c_str(), makeArrayString(arrayLiteralValues()).c_str()); case NEW: return makeString("New(placementArg: %s, operand: %s)", newPlacementArg().toString().c_str(), newOperand().toString().c_str()); case CASTDUMMYOBJECT: return makeString("[CAST DUMMY OBJECT (FOR SEMANTIC ANALYSIS)](type: %s)", type()->toString().c_str()); } locic_unreachable("Unknown value kind."); }
bool Value::operator==(const Value& value) const { if (kind() != value.kind()) { return false; } if (type() != value.type()) { return false; } switch (value.kind()) { case Value::SELF: return true; case Value::THIS: return true; case Value::CONSTANT: return constant() == value.constant(); case Value::ALIAS: return &(alias()) == &(value.alias()) && aliasTemplateArguments() == value.aliasTemplateArguments(); case Value::PREDICATE: return predicate() == value.predicate(); case Value::LOCALVAR: return &(localVar()) == &(value.localVar()); case Value::REINTERPRET: return reinterpretOperand() == value.reinterpretOperand(); case Value::DEREF_REFERENCE: return derefOperand() == value.derefOperand(); case Value::TERNARY: return ternaryCondition() == value.ternaryCondition() && ternaryIfTrue() == value.ternaryIfTrue() && ternaryIfFalse() == value.ternaryIfFalse(); case Value::CAST: return castTargetType() == value.castTargetType() && castOperand() == value.castOperand(); case Value::POLYCAST: return polyCastTargetType() == value.polyCastTargetType() && polyCastOperand() == value.polyCastOperand(); case Value::INTERNALCONSTRUCT: return internalConstructParameters() == value.internalConstructParameters(); case Value::MEMBERACCESS: return memberAccessObject() == value.memberAccessObject() && &(memberAccessVar()) == &(value.memberAccessVar()); case Value::BIND_REFERENCE: return bindReferenceOperand() == value.bindReferenceOperand(); case Value::TYPEREF: return typeRefType() == value.typeRefType(); case Value::TEMPLATEVARREF: return templateVar() == value.templateVar(); case Value::CALL: return callValue() == value.callValue() && callParameters() == value.callParameters(); case Value::FUNCTIONREF: return functionRefParentType() == value.functionRefParentType() && &(functionRefFunction()) == &(value.functionRefFunction()) && functionRefTemplateArguments() == value.functionRefTemplateArguments(); case Value::TEMPLATEFUNCTIONREF: return templateFunctionRefParentType() == value.templateFunctionRefParentType() && templateFunctionRefName() == value.templateFunctionRefName() && templateFunctionRefFunctionType() == value.templateFunctionRefFunctionType(); case Value::METHODOBJECT: return methodObject() == value.methodObject() && methodOwner() == value.methodOwner(); case Value::INTERFACEMETHODOBJECT: return interfaceMethodObject() == value.interfaceMethodObject() && interfaceMethodOwner() == value.interfaceMethodOwner(); case Value::STATICINTERFACEMETHODOBJECT: return staticInterfaceMethodObject() == value.staticInterfaceMethodObject() && staticInterfaceMethodOwner() == value.staticInterfaceMethodOwner(); case Value::CAPABILITYTEST: return capabilityTestCheckType() == value.capabilityTestCheckType() && capabilityTestCapabilityType() == value.capabilityTestCapabilityType(); case Value::ARRAYLITERAL: return arrayLiteralValues() == value.arrayLiteralValues(); case Value::NEW: return newPlacementArg() == value.newPlacementArg() && newOperand() == value.newOperand(); case Value::CASTDUMMYOBJECT: return true; } locic_unreachable("Unknown value kind."); }
size_t Value::hash() const { Hasher hasher; hasher.add(kind()); hasher.add(type()); switch (kind()) { case Value::SELF: break; case Value::THIS: break; case Value::CONSTANT: hasher.add(constant()); break; case Value::ALIAS: hasher.add(&(alias())); hasher.add(aliasTemplateArguments().size()); for (const auto& argument: aliasTemplateArguments()) { hasher.add(argument); } break; case Value::PREDICATE: hasher.add(predicate()); break; case Value::LOCALVAR: hasher.add(&(localVar())); break; case Value::REINTERPRET: hasher.add(reinterpretOperand()); break; case Value::DEREF_REFERENCE: hasher.add(derefOperand()); break; case Value::TERNARY: hasher.add(ternaryCondition()); hasher.add(ternaryIfTrue()); hasher.add(ternaryIfFalse()); break; case Value::CAST: hasher.add(castTargetType()); hasher.add(castOperand()); break; case Value::POLYCAST: hasher.add(polyCastTargetType()); hasher.add(polyCastOperand()); break; case Value::INTERNALCONSTRUCT: hasher.add(internalConstructParameters().size()); for (const auto& param: internalConstructParameters()) { hasher.add(param); } break; case Value::MEMBERACCESS: hasher.add(memberAccessObject()); hasher.add(&(memberAccessVar())); break; case Value::BIND_REFERENCE: hasher.add(bindReferenceOperand()); break; case Value::TYPEREF: hasher.add(typeRefType()); break; case Value::TEMPLATEVARREF: hasher.add(templateVar()); break; case Value::CALL: hasher.add(callValue()); hasher.add(callParameters().size()); for (const auto& param: callParameters()) { hasher.add(param); } break; case Value::FUNCTIONREF: hasher.add(functionRefParentType()); hasher.add(&(functionRefFunction())); hasher.add(functionRefTemplateArguments().size()); for (const auto& arg: functionRefTemplateArguments()) { hasher.add(arg); } break; case Value::TEMPLATEFUNCTIONREF: hasher.add(templateFunctionRefParentType()); hasher.add(templateFunctionRefName()); hasher.add(templateFunctionRefFunctionType()); break; case Value::METHODOBJECT: hasher.add(methodObject()); hasher.add(methodOwner()); break; case Value::INTERFACEMETHODOBJECT: hasher.add(interfaceMethodObject()); hasher.add(interfaceMethodOwner()); break; case Value::STATICINTERFACEMETHODOBJECT: hasher.add(staticInterfaceMethodObject()); hasher.add(staticInterfaceMethodOwner()); break; case Value::CAPABILITYTEST: hasher.add(capabilityTestCheckType()); hasher.add(capabilityTestCapabilityType()); break; case Value::ARRAYLITERAL: hasher.add(arrayLiteralValues().size()); for (const auto& value: arrayLiteralValues()) { hasher.add(value); } break; case Value::NEW: hasher.add(newPlacementArg()); hasher.add(newOperand()); break; case Value::CASTDUMMYOBJECT: break; } return hasher.get(); }
std::string Value::toDiagString() const { switch (kind()) { case SELF: return "self"; case THIS: return "this"; case CONSTANT: return constant().toString(); case ALIAS: return alias().toString(); case PREDICATE: return predicate().toString(); case LOCALVAR: return localVar().name().asStdString(); case REINTERPRET: return reinterpretOperand().toDiagString(); case DEREF_REFERENCE: return makeString("<deref> %s", derefOperand().toDiagString().c_str()); case TERNARY: return makeString("%s ? %s : %s", ternaryCondition().toDiagString().c_str(), ternaryIfTrue().toDiagString().c_str(), ternaryIfFalse().toDiagString().c_str()); case CAST: return castOperand().toDiagString(); case POLYCAST: return polyCastOperand().toDiagString(); case INTERNALCONSTRUCT: return makeString("@(%s)", makeArrayString(internalConstructParameters()).c_str()); case MEMBERACCESS: return makeString("%s.%s", memberAccessObject().toDiagString().c_str(), memberAccessVar().name().c_str()); case BIND_REFERENCE: return makeString("<bind> %s", bindReferenceOperand().toDiagString().c_str()); case TYPEREF: return typeRefType()->toDiagString(); case TEMPLATEVARREF: return templateVar()->fullName().last().asStdString(); case CALL: return makeString("%s(%s)", callValue().toDiagString().c_str(), makeArrayString(callParameters()).c_str()); case FUNCTIONREF: return functionRefFunction().fullName().toString(); case TEMPLATEFUNCTIONREF: return makeString("%s::%s", templateFunctionRefParentType()->toDiagString().c_str(), templateFunctionRefName().c_str()); case METHODOBJECT: return makeString("%s.%s", methodOwner().toDiagString().c_str(), methodObject().toDiagString().c_str()); case INTERFACEMETHODOBJECT: return makeString("%s.%s", interfaceMethodOwner().toDiagString().c_str(), interfaceMethodObject().toDiagString().c_str()); case STATICINTERFACEMETHODOBJECT: return makeString("%s.%s", staticInterfaceMethodOwner().toDiagString().c_str(), staticInterfaceMethodObject().toDiagString().c_str()); case CAPABILITYTEST: return makeString("%s : %s", capabilityTestCheckType()->toDiagString().c_str(), capabilityTestCapabilityType()->toDiagString().c_str()); case Value::ARRAYLITERAL: return makeString("{ %s }", makeArrayString(arrayLiteralValues()).c_str()); case NEW: return makeString("new(%s) %s", newPlacementArg().toDiagString().c_str(), newOperand().toDiagString().c_str()); case CASTDUMMYOBJECT: locic_unreachable("Shouldn't reach CASTDUMMYOBJECT."); } locic_unreachable("Unknown value kind."); }
/** * @brief Computes the FuncInfo and returns it. */ ShPtr<OptimFuncInfo> OptimFuncInfoCFGTraversal::performComputation() { // First, we pre-compute varsAlwaysModifiedBeforeRead. The reason is that // their computation differs from the computation of the rest of the sets. precomputeAlwaysModifiedVarsBeforeRead(); // Every function's body is of the following form: // // (1) definitions of local variables, including assignments of global // variables into local variables // (2) other statements // // We store which variables are read/modified in (1). Then, we start the // traversal from (2). During the traversal, we check which variables are // read/modified and update funcInfo accordingly. The stored information // from (1) is used to compute the set of global variables which are read // in the function, but not modified. // // To give a specific example, consider the following code: // // def func(mango): // global orange // global plum // lychee = orange // achira = plum // orange = mango // plum = rand() // result = plum * apple + orange // orange = lychee // plum = achira // return result // // Here, even though the global variable orange is modified, its value // before calling func() is the same as after calling func(). Indeed, its // value is restored before the return statement. Hence, we may put it into // funcInfo->varsWithNeverChangedValue. // TODO Implement a more robust analysis. ShPtr<Statement> currStmt = traversedFunc->getBody(); while (isVarDefOrAssignStmt(currStmt)) { updateFuncInfo(currStmt); ShPtr<Expression> lhs(getLhs(currStmt)); ShPtr<Expression> rhs(getRhs(currStmt)); // If there is no right-hand side, it is a VarDefStmt with no // initializer, which we may skip. if (!rhs) { currStmt = currStmt->getSuccessor(); continue; } // If there are any function calls or dereferences, we have reached // (2). ShPtr<ValueData> currStmtData(va->getValueData(currStmt)); if (currStmtData->hasCalls() || currStmtData->hasDerefs()) { break; } // Check whether the statement is of the form localVar = globalVar. ShPtr<Variable> localVar(cast<Variable>(lhs)); ShPtr<Variable> globalVar(cast<Variable>(rhs)); if (!localVar || !globalVar || hasItem(globalVars, localVar) || !hasItem(globalVars, globalVar)) { // It is not of the abovementioned form, so skip it. currStmt = currStmt->getSuccessor(); continue; } storedGlobalVars[globalVar] = localVar; currStmt = currStmt->getSuccessor(); } // Perform the traversal only if we haven't reached the end of the function // yet. Since empty statements are not present in a CFG, skip them before // the traversal. if ((currStmt = skipEmptyStmts(currStmt))) { performTraversal(currStmt); } // We use the exit node of the CFG to check that every variable from // storedGlobalVars is retrieved its original value before every return. ShPtr<CFG::Node> exitNode(cfg->getExitNode()); // For every predecessor of the exit node... for (auto i = exitNode->pred_begin(), e = exitNode->pred_end(); i != e; ++i) { bool checkingShouldContinue = checkExitNodesPredecessor((*i)->getSrc()); if (!checkingShouldContinue) { break; } } // Update funcInfo using the remaining variables in storedGlobalVars. for (const auto &p : storedGlobalVars) { funcInfo->varsWithNeverChangedValue.insert(p.first); } // Update funcInfo->never{Read,Modified}Vars by global variables which are // untouched in this function. for (auto i = module->global_var_begin(), e = module->global_var_end(); i != e; ++i) { ShPtr<Variable> var((*i)->getVar()); if (!hasItem(funcInfo->mayBeReadVars, var) && !hasItem(funcInfo->mayBeModifiedVars, var)) { funcInfo->neverReadVars.insert(var); funcInfo->neverModifiedVars.insert(var); } } // If the cfg contains only a single non-{entry,exit} node, every // mayBe{Read,Modifed} variable can be turned into a always{Read,Modified} // variable. if (cfg->getNumberOfNodes() == 3) { addToSet(funcInfo->mayBeReadVars, funcInfo->alwaysReadVars); addToSet(funcInfo->mayBeModifiedVars, funcInfo->alwaysModifiedVars); } // Add all variables which are never read and never modified to // varsWithNeverChangedValue. VarSet neverReadAndModifedVars(setIntersection(funcInfo->neverReadVars, funcInfo->neverModifiedVars)); addToSet(neverReadAndModifedVars, funcInfo->varsWithNeverChangedValue); // Add all global variables are not read in this function into // varsAlwaysModifiedBeforeRead. addToSet(setDifference(globalVars, funcInfo->mayBeReadVars), funcInfo->varsAlwaysModifiedBeforeRead); return funcInfo; }