llvm::Value* ModelDataLoadSymbolResolver::loadSymbolValue( const std::string& symbol, const llvm::ArrayRef<llvm::Value*>& args) { ModelDataIRBuilder mdbuilder(modelData, modelDataSymbols, builder); /*************************************************************************/ /* time */ /*************************************************************************/ if (symbol.compare(SBML_TIME_SYMBOL) == 0) { Value *timeEP = mdbuilder.createGEP(Time); Value *time = builder.CreateLoad(timeEP, SBML_TIME_SYMBOL); return time; } /*************************************************************************/ /* Function */ /*************************************************************************/ { Value *funcVal = FunctionResolver(*this, model, builder).loadSymbolValue(symbol, args); if (funcVal) { return funcVal; } } /*************************************************************************/ /* AssignmentRule */ /*************************************************************************/ { SymbolForest::ConstIterator i = modelSymbols.getAssigmentRules().find( symbol); if (i != modelSymbols.getAssigmentRules().end()) { recursiveSymbolPush(symbol); Value* result = ASTNodeCodeGen(builder, *this).codeGen(i->second); recursiveSymbolPop(); return result; } } /*************************************************************************/ /* Species */ /*************************************************************************/ const Species *species = model->getSpecies(symbol); if (species) { Value *amt = 0; if (modelDataSymbols.isIndependentFloatingSpecies(symbol)) { amt = mdbuilder.createFloatSpeciesAmtLoad(symbol, symbol + "_amt"); } else if (modelDataSymbols.isIndependentBoundarySpecies(symbol)) { amt = mdbuilder.createBoundSpeciesAmtLoad(symbol, symbol + "_amt"); } else if(modelDataSymbols.hasRateRule(symbol)) { amt = mdbuilder.createRateRuleValueLoad(symbol, symbol + "_amt"); } else { string msg = string("the symbol ") + symbol + string(" appeared to " "be a species, but it could not be found as an independent " "species or rate rule"); throw_llvm_exception(msg); } assert(amt); // now we have an amount, check to see if we need to convert to conc if (species->getHasOnlySubstanceUnits()) { return amt; } else { // expect a concentration, need to convert amt to conc, // so we need to get the compartment its in, but these // can vary also... Value *comp = loadSymbolValue(species->getCompartment()); return builder.CreateFDiv(amt, comp, symbol + "_conc"); } } if (modelDataSymbols.isIndependentCompartment(symbol)) { return mdbuilder.createCompLoad(symbol); } if (modelDataSymbols.isIndependentGlobalParameter(symbol)) { return mdbuilder.createGlobalParamLoad(symbol); } if (modelDataSymbols.hasRateRule(symbol)) { // species conc / amt has already been taken care of at this point return mdbuilder.createRateRuleValueLoad(symbol); } if (modelDataSymbols.isNamedSpeciesReference(symbol)) { const LLVMModelDataSymbols::SpeciesReferenceInfo &info = modelDataSymbols.getNamedSpeciesReferenceInfo(symbol); Value *value = mdbuilder.createStoichiometryLoad(info.row, info.column, symbol); if (info.type == LLVMModelDataSymbols::MultiReactantProduct) { string msg = "mutable stochiometry for species which appear " "multiple times in a single reaction is not currently " "supported, species reference id: "; msg += symbol; throw_llvm_exception(msg); } if (info.type == LLVMModelDataSymbols::Reactant) { // its consumed in the reaction, so has a negative in the stoich // matrix Value *negOne = ConstantFP::get(builder.getContext(), APFloat(-1.0)); negOne->setName("neg_one"); value = builder.CreateFMul(negOne, value, "neg_" + symbol); } return value; } /*************************************************************************/ /* Reaction Rate */ /*************************************************************************/ const Reaction* reaction = model->getReaction(symbol); if (reaction) { return loadReactionRate(reaction); } string msg = "the symbol \'"; msg += symbol; msg += "\' is not physically stored in the ModelData structure, " "it either does not exists or is defined by an assigment rule (hence it " "is not a terminal symbol)"; throw_llvm_exception(msg); return 0; }
int SSPParser::getNextToken(void *Val) { YYSTYPE *Value = static_cast<YYSTYPE*>(Val); StringRef BufferData = Buf->getBuffer(); const char *Data = BufferData.data(); const char* CurCh = Data+CurPos; while (CurPos < BufferData.size() && (*CurCh == '\t' || *CurCh == ' ' || *CurCh == '\r' || *CurCh == '\n')) { CurPos++; CurCh = Data+CurPos; } if (CurPos >= BufferData.size()) return 0; // EOF if (*CurCh == '+') { CurPos++; return PLUS; } else if (*CurCh == '-') { CurPos++; return MINUS; } else if (*CurCh == '*') { CurPos++; return ASTERISK; } else if (*CurCh == '/') { CurPos++; return SLASH; } else if (*CurCh == '$') { CurPos++; return DOLLAR; } else if (*CurCh == '@') { CurPos++; return AT; } else if (IsAlpha(*CurCh)) { const char *Start = CurCh; size_t Length = 0; do { Length++; CurPos++; CurCh = Data+CurPos; } while (CurPos < BufferData.size() && (IsAlphaOrDigit(*CurCh) || *CurCh == '_')); StringRef *Str = new StringRef(Start, Length); // Check for keywords if (Str->compare("double") == 0) { return DOUBLE; } else if (Str->compare("field") == 0) { return FIELD; } else if (Str->compare("float") == 0) { return FLOAT; } else if (Str->compare("grid") == 0) { return GRID; } else if (Str->compare("in") == 0) { return IN; } else if (Str->compare("inout") == 0) { return INOUT; } else if (Str->compare("is") == 0) { return IS; } else if (Str->compare("let") == 0) { return LET; } else if (Str->compare("out") == 0) { return OUT; } else if (Str->compare("param") == 0) { return PARAM; } else if (Str->compare("program") == 0) { return PROGRAM; } // Not a keyword InternedStrings.push_back(Str); Value->Ident = Str; return IDENT; } else if (IsDigit(*CurCh)) { const char *Start = CurCh; size_t Length = 0; bool IsFloat = false; do { if (*CurCh == '.') IsFloat = true; Length++; CurPos++; CurCh = Data+CurPos; } while (CurPos < BufferData.size() && (IsDigit(*CurCh) || *CurCh == '.')); if (CurPos < BufferData.size() && (*CurCh == 'e' || *CurCh == 'E')) { // Start of an exponent IsFloat = true; CurPos++; CurCh = Data+CurPos; Length++; if (CurPos == BufferData.size() || (!IsDigit(*CurCh) && *CurCh != '-')) { SrcMgr.PrintMessage(SMLoc::getFromPointer(Data+CurPos), SourceMgr::DK_Error, "Missing exponent"); return 0; } if (*CurCh == '-') { Length++; CurPos++; CurCh = Data+CurPos; if (CurPos == BufferData.size() || !IsDigit(*CurCh)) { SrcMgr.PrintMessage(SMLoc::getFromPointer(Data+CurPos), SourceMgr::DK_Error, "Missing exponent"); return 0; } } do { Length++; CurPos++; CurCh = Data+CurPos; } while (CurPos < BufferData.size() && IsDigit(*CurCh)); } StringRef Str = StringRef(Start, Length); if (IsFloat) { APFloat DoubleValue = APFloat(APFloat::IEEEdouble, Str); Value->DoubleConst = DoubleValue.convertToDouble(); return DOUBLECONST; } else { long IntValue = atol(Str.data()); Value->IntConst = IntValue; return INTCONST; } } else if (*CurCh == '=') { CurPos++; return EQUALS; } else if (*CurCh == '(') { CurPos++; return OPENPARENS; } else if (*CurCh == ')') { CurPos++; return CLOSEPARENS; } else if (*CurCh == '[') { CurPos++; return OPENBRACE; } else if (*CurCh == ']') { CurPos++; return CLOSEBRACE; } else if (*CurCh == ',') { CurPos++; return COMMA; } else if (*CurCh == ':') { CurPos++; return COLON; } CurPos++; // If we get here, then we have no idea how to lex this! printError("Unknown symbol"); return 0; }
llvm::Value* ModelDataStoreSymbolResolver::storeSymbolValue( const std::string& symbol, llvm::Value *value) { assert(value); ModelDataIRBuilder mdbuilder(modelData, modelDataSymbols, builder); /*************************************************************************/ /* AssignmentRule */ /*************************************************************************/ // can not store anything with an assigment rule, these are determined // by other independent elements. if (modelDataSymbols.hasAssignmentRule(symbol)) { throw_llvm_exception("Attempt to store a value in symbol \"" + symbol + "\" which is defined by an assignemnt rule"); } /*************************************************************************/ /* Species */ /*************************************************************************/ const Species *species = model->getSpecies(symbol); if (species) { Value *amt = 0; // only amounts are stored, convert to conc if required if (species->getHasOnlySubstanceUnits()) { amt = value; } else { // have a conc, need to convert to amt Value *comp = resolver.loadSymbolValue(species->getCompartment()); amt = builder.CreateFMul(value, comp, symbol + "_amt"); } assert(amt); // now look where we need to store it if (modelDataSymbols.isIndependentFloatingSpecies(symbol)) { return mdbuilder.createFloatSpeciesAmtStore(symbol, amt); } else if (modelDataSymbols.isIndependentBoundarySpecies(symbol)) { return mdbuilder.createBoundSpeciesAmtStore(symbol, amt); } else if(modelDataSymbols.hasRateRule(symbol)) { return mdbuilder.createRateRuleValueStore(symbol, amt); } else { string msg = string("the symbol ") + symbol + string(" appeared to " "be a species, but it could not be found as an independent " "species or rate rule"); throw_llvm_exception(msg); return 0; } } // at this point, we have already taken care of the species amount / // conc conversion, rest are just plain stores. if (modelDataSymbols.hasRateRule(symbol)) { return mdbuilder.createRateRuleValueStore(symbol, value); } else if (modelDataSymbols.isIndependentCompartment(symbol)) { return mdbuilder.createCompStore(symbol, value); } else if (modelDataSymbols.isIndependentGlobalParameter(symbol)) { return mdbuilder.createGlobalParamStore(symbol, value); } else if (modelDataSymbols.isNamedSpeciesReference(symbol)) { const LLVMModelDataSymbols::SpeciesReferenceInfo &info = modelDataSymbols.getNamedSpeciesReferenceInfo(symbol); if (info.type == LLVMModelDataSymbols::MultiReactantProduct) { string msg = "mutable stochiometry for species which appear " "multiple times in a single reaction is not currently " "supported, species reference id: "; msg += symbol; throw_llvm_exception(msg); } if (info.type == LLVMModelDataSymbols::Reactant) { // its consumed in the reaction, so has a negative in the stoich // matrix Value *negOne = ConstantFP::get(builder.getContext(), APFloat(-1.0)); negOne->setName("neg_one"); value = builder.CreateFMul(negOne, value, "neg_" + symbol); } return mdbuilder.createStoichiometryStore(info.row, info.column, value); } string msg = "The symbol \'"; msg += symbol; msg += "\' is not physically stored in the ModelData structure, " "it either does not exists or is defined by an assigment rule (hence it " "is not a terminal symbol)"; throw_llvm_exception(msg); return 0; }
llvm::Value* Unop::Codegen(WasmFunction* fct, llvm::IRBuilder<>& builder) { bool is_intrinsic = false; OPERATION op = operation_->GetOperation(); switch (op) { case CLZ_OPER: case CTZ_OPER: case POPCNT_OPER: case SQRT_OPER: case ABS_OPER: case CEIL_OPER: case FLOOR_OPER: case NEAREST_OPER: is_intrinsic = true; break; case TRUNC_OPER: { // Use the intrinsic value if we have the same type. // Basically this is used for f32.trunc or f64.trunc... ConversionOperation* conversion = dynamic_cast<ConversionOperation*>(operation_); assert(conversion != nullptr); is_intrinsic = (conversion->GetSrc() == conversion->GetDest()); break; } default: break; } if (is_intrinsic == true) { WasmModule* wasm_module = fct->GetModule(); ETYPE type = operation_->GetType(); llvm::Intrinsic::ID intrinsic; bool extra_true_arg = false; switch (op) { case CLZ_OPER: intrinsic = llvm::Intrinsic::ctlz; // We need to pass true as second argument to produce defined result for zero. extra_true_arg = true; break; case CTZ_OPER: intrinsic = llvm::Intrinsic::cttz; // We need to pass true as second argument to produce defined result for zero. extra_true_arg = true; break; case POPCNT_OPER: intrinsic = llvm::Intrinsic::ctpop; break; case SQRT_OPER: intrinsic = llvm::Intrinsic::sqrt; break; case ABS_OPER: intrinsic = llvm::Intrinsic::fabs; break; case CEIL_OPER: intrinsic = llvm::Intrinsic::ceil; break; case FLOOR_OPER: intrinsic = llvm::Intrinsic::floor; break; case TRUNC_OPER: intrinsic = llvm::Intrinsic::trunc; break; case NEAREST_OPER: intrinsic = llvm::Intrinsic::nearbyint; break; default: assert(0); return nullptr; } llvm::Function* intrinsic_fct = wasm_module->GetOrCreateIntrinsic(intrinsic, type); assert(intrinsic_fct != nullptr); std::vector<Value*> arg; arg.push_back(only_->Codegen(fct, builder)); if (extra_true_arg) { llvm::Value* val_true = llvm::ConstantInt::get(llvm::getGlobalContext(), APInt(1, 0, false)); arg.push_back(val_true); } return builder.CreateCall(intrinsic_fct, arg, "calltmp"); } else { llvm::Value* rv = only_->Codegen(fct, builder); ETYPE type = operation_->GetType(); switch (op) { case NEG_OPER: { llvm::Value* lv; if (type == FLOAT_32) { lv = llvm::ConstantFP::get(llvm::getGlobalContext(), APFloat(0.0f)); } else { lv = llvm::ConstantFP::get(llvm::getGlobalContext(), APFloat(0.0)); } return builder.CreateFSub(lv, rv, "subtmp"); } case REINTERPRET_OPER: return builder.CreateBitCast(rv, ConvertType(type), DumpOperation(op)); case EXTEND_OPER: case TRUNC_OPER: case PROMOTE_OPER: case DEMOTE_OPER: case CONVERT_OPER: case WRAP_OPER: { ConversionOperation* conversion = dynamic_cast<ConversionOperation*>(operation_); assert(conversion != nullptr); return HandleTypeCasts(rv, ConvertType(conversion->GetSrc()), ConvertType(type), operation_->GetSignedOrOrdered(), builder); } } assert(0); return nullptr; } }
llvm::Value* ModelInitialValueSymbolResolver::loadSymbolValue( const std::string& symbol, const llvm::ArrayRef<llvm::Value*>& args) { ModelDataIRBuilder mdbuilder(modelData, modelDataSymbols, builder); /*************************************************************************/ /* time */ /*************************************************************************/ if (symbol.compare(SBML_TIME_SYMBOL) == 0) { return ConstantFP::get(builder.getContext(), APFloat(0.0)); } /*************************************************************************/ /* Function */ /*************************************************************************/ { Value *funcVal = FunctionResolver(*this, model, builder).loadSymbolValue(symbol, args); if (funcVal) { return funcVal; } } /*************************************************************************/ /* Initial AssignmentRule */ /*************************************************************************/ { SymbolForest::ConstIterator i = modelSymbols.getInitialAssignmentRules().find(symbol); if (i != modelSymbols.getInitialAssignmentRules().end()) { recursiveSymbolPush(symbol); Value* result = ASTNodeCodeGen(builder, *this).codeGen(i->second); recursiveSymbolPop(); return result; } } /*************************************************************************/ /* AssignmentRule */ /*************************************************************************/ if (!modelDataSymbols.isConservedMoietySpecies(symbol)) { SymbolForest::ConstIterator i = modelSymbols.getAssigmentRules().find(symbol); if (i != modelSymbols.getAssigmentRules().end()) { return ASTNodeCodeGen(builder, *this).codeGen(i->second); } } if (modelDataSymbols.isIndependentInitFloatingSpecies(symbol)) { const Species *species = model->getSpecies(symbol); assert(species); Value *amt = mdbuilder.createInitFloatSpeciesAmtLoad(symbol, symbol + "_amt"); // now we have an amount, check to see if we need to convert to conc if (species->getHasOnlySubstanceUnits()) { return amt; } else { // expect a concentration, need to convert amt to conc, // so we need to get the compartment its in, but these // can vary also... Value *comp = loadSymbolValue(species->getCompartment()); return builder.CreateFDiv(amt, comp, symbol + "_conc"); } } else if (modelDataSymbols.isIndependentCompartment(symbol)) { return mdbuilder.createInitCompLoad(symbol); } /*************************************************************************/ /* Initial Value */ /*************************************************************************/ { SymbolForest::ConstIterator i = modelSymbols.getInitialValues().find(symbol); if (i != modelSymbols.getInitialValues().end()) { return ASTNodeCodeGen(builder, *this).codeGen(i->second); } } /*************************************************************************/ /* Reaction Rate */ /*************************************************************************/ const Reaction* reaction = model->getReaction(symbol); if (reaction) { return loadReactionRate(reaction); } string msg = "Could not find requested symbol \'"; msg += symbol; msg += "\' in the model"; throw_llvm_exception(msg); return 0; }
void *LLVMFormula::emit (CallExprAST *expr) { // Deal with the if-instruction first, specially if (expr->function == "if") { Value *cond = (Value *)expr->args[0]->generate (this); Value *t = (Value *)expr->args[1]->generate (this); Value *f = (Value *)expr->args[2]->generate (this); if (cond == NULL || t == NULL || f == NULL) return NULL; Value *one = ConstantFP::get (getGlobalContext (), APFloat (1.0)); Value *cmp = builder->CreateFCmpOEQ (cond, one, "ifcmptmp"); return builder->CreateSelect (cmp, t, f, "ifelsetmp"); } // Sign isn't a standard-library function, implement it with a compare if (expr->function == "sign") { Value *v = (Value *)expr->args[0]->generate (this); if (!v) return NULL; Value *zero = ConstantFP::get (getGlobalContext (), APFloat (0.0)); Value *one = ConstantFP::get (getGlobalContext (), APFloat (1.0)); Value *none = ConstantFP::get (getGlobalContext (), APFloat (-1.0)); Value *cmpgzero = builder->CreateFCmpOGT (v, zero, "sgncmpgzero"); Value *cmplzero = builder->CreateFCmpOLT (v, zero, "sgncmplzero"); Value *fselect = builder->CreateSelect (cmplzero, none, zero, "sgnsellzero"); return builder->CreateSelect (cmpgzero, one, fselect, "sgnselgzero"); } // // Map our function names to standard libm names // // If we're calling "log", we want "log10" if (expr->function == "log") expr->function = "log10"; // If we're calling "ln", we want "log" if (expr->function == "ln") expr->function = "log"; // If we're calling "abs", we want "fabs" if (expr->function == "abs") expr->function = "fabs"; // The following are available as LLVM intrinsics, and we should emit them // specially without calling out to libm: Intrinsic::ID intrinsicID = Intrinsic::not_intrinsic; if (expr->function == "cos") intrinsicID = Intrinsic::cos; else if (expr->function == "exp") intrinsicID = Intrinsic::exp; else if (expr->function == "log") intrinsicID = Intrinsic::log; else if (expr->function == "log10") intrinsicID = Intrinsic::log10; else if (expr->function == "sin") intrinsicID = Intrinsic::sin; else if (expr->function == "sqrt") intrinsicID = Intrinsic::sqrt; if (intrinsicID != Intrinsic::not_intrinsic) { // Most of the floating-point intrinsics are overloaded for multiple types Type *types[1] = { Type::getDoubleTy (getGlobalContext ()) }; ArrayRef<Type *> type_array(types, 1); Value *arg = (Value *)expr->args[0]->generate (this); if (!arg) return NULL; Value *func = Intrinsic::getDeclaration (module, intrinsicID, type_array); return builder->CreateCall (func, arg, expr->function); } // The rest of these are calls to stdlib floating point math // functions. // atan2 is special, because it has two arguments if (expr->function == "atan2") { Value *arg1 = (Value *)expr->args[0]->generate (this); Value *arg2 = (Value *)expr->args[1]->generate (this); if (!arg1 || !arg2) return NULL; Module *M = builder->GetInsertBlock ()->getParent ()->getParent (); Value *Callee = M->getOrInsertFunction (expr->function, Type::getDoubleTy (getGlobalContext ()), Type::getDoubleTy (getGlobalContext ()), Type::getDoubleTy (getGlobalContext ()), NULL); return builder->CreateCall2 (Callee, arg1, arg2, expr->function); } else { // Emit a call to function (arg) Value *arg = (Value *)expr->args[0]->generate (this); if (!arg) return NULL; Module *M = builder->GetInsertBlock ()->getParent ()->getParent (); Value *Callee = M->getOrInsertFunction (expr->function, Type::getDoubleTy (getGlobalContext ()), Type::getDoubleTy (getGlobalContext ()), NULL); return builder->CreateCall (Callee, arg, expr->function); } }
void *LLVMFormula::emit (NumberExprAST *expr) { return ConstantFP::get (getGlobalContext (), APFloat (expr->val)); }
Value* getDouble(double v){ return ConstantFP::get(context_, APFloat(v)); }