void ExportPass::AddSymbols() { assert(repository != NULL) ; assert(constructedType != NULL) ; assert(constructedSymbol != NULL) ; // By this point, the repository has been read in and the symbol table // has been completely overwritten. SymbolTable* symTab = repository->get_external_symbol_table() ; assert(symTab != NULL) ; DataType* resultType = constructedType->get_result_type() ; bool resultReplaced = false ; for (int j = 0 ; j < symTab->get_symbol_table_object_count() ; ++j) { DataType* existingType = dynamic_cast<DataType*>(symTab->get_symbol_table_object(j)) ; if (existingType != NULL && EquivalentTypes(resultType, existingType)) { constructedType->set_result_type(existingType) ; resultReplaced = true ; delete resultType ; break ; } } if (!resultReplaced) { symTab->append_symbol_table_object(resultType) ; } // Go through all of the arguments and replace them with appropriate types // if they already exist in the symbol table. for (int i = 0 ; i < constructedType->get_argument_count() ; ++i) { QualifiedType* currentArg = constructedType->get_argument(i) ; assert(currentArg != NULL) ; bool replaced = false ; for (int j = 0 ; j < symTab->get_symbol_table_object_count() ; ++j) { QualifiedType* existingType = dynamic_cast<QualifiedType*>(symTab->get_symbol_table_object(j)) ; if (existingType != NULL && EquivalentTypes(currentArg, existingType) && existingType->get_annote_count() == currentArg->get_annote_count()) { constructedType->replace_argument(i, existingType) ; replaced = true ; break ; } } if (replaced == false) { symTab->append_symbol_table_object(currentArg) ; symTab->append_symbol_table_object(currentArg->get_base_type()) ; } } symTab->append_symbol_table_object(constructedType) ; symTab->append_symbol_table_object(constructedSymbol) ; }
bool SpCandidate::isMoreSpecific(const SpCandidate * other) const { const Template * tm = def_->templateSignature(); const Template * otm = other->def_->templateSignature(); if (tm->typeParams()->size() != otm->typeParams()->size()) { return false; } bool same = true; size_t numParams = tm->typeParams()->size(); for (size_t i = 0; i < numParams; ++i) { QualifiedType param = tm->typeParam(i); QualifiedType oparam = otm->typeParam(i); if (!TypeRelation::isEqual(param, oparam)) { same = false; if (!TypeRelation::isSubtype(param, oparam)) { if (oparam->typeClass() != Type::TypeVar) { return false; } // TODO: CanBind check here... } } } if (same) { // TODO A temporary kludge. if (!def_->hasUnboundTypeParams() && other->def_->hasUnboundTypeParams()) { return true; } } return !same; }
static QualifiedType returnInfoFirstDeref(CallExpr* call) { QualifiedType tmp = call->get(1)->qualType(); Type* type = tmp.type()->getValType(); // if it's a tuple, also remove references in the elements if (type->symbol->hasFlag(FLAG_TUPLE)) { type = computeNonRefTuple(type); } return QualifiedType(type, QUAL_VAL); }
QualifiedType AmbiguousTypeParamType::forType(QualifiedType base, const Type * match, unsigned paramIndex) { base = dealias(base); match = dealias(match); switch (base->typeClass()) { case Type::Class: case Type::Struct: case Type::Interface: case Type::Protocol: { const CompositeType * ctBase = static_cast<const CompositeType *>(base.type()); if (const CompositeType * ctMatch = dyn_cast_or_null<CompositeType>(match)) { if (ctMatch != NULL) { base = ctBase->findBaseSpecializing(ctMatch); if (!base) { return QualifiedType(); } } if (paramIndex >= base->numTypeParams()) { return QualifiedType(); } else { return base->typeParam(paramIndex); } } return QualifiedType(); } case Type::NAddress: case Type::NArray: case Type::FlexibleArray: { if (paramIndex == 0 && (match == NULL || base->typeClass() == match->typeClass())) { return base->typeParam(0); } return QualifiedType(); } case Type::Tuple: { if (match != NULL || paramIndex >= base->numTypeParams()) { return QualifiedType(); } else { return base->typeParam(paramIndex); } } case Type::AmbiguousParameter: case Type::AmbiguousResult: case Type::AmbiguousTypeParam: case Type::AmbiguousPhi: case Type::Assignment: { QualifiedTypeSet expansion; base.expand(expansion); if (expansion.size() == 1) { return forType(*expansion.begin(), match, paramIndex); } return new AmbiguousTypeParamType(base, match, paramIndex); } default: return QualifiedType(); } }
bool TypeSetConstraint::isReferenceType() const { QualifiedTypeSet expansion; expandImpl(expansion, 0); for (QualifiedTypeSet::iterator it = expansion.begin(); it != expansion.end(); ++it) { QualifiedType ty = *it; if (!ty->isReferenceType()) { return false; } } return true; }
void AmbiguousTypeParamType::expandImpl(QualifiedTypeSet & out, unsigned qualifiers) const { QualifiedTypeSet baseExpansion; base_.expand(baseExpansion); for (QualifiedTypeSet::iterator it = baseExpansion.begin(); it != baseExpansion.end(); ++it) { QualifiedType ty = forType(*it, match_, paramIndex_); if (ty) { ty.expand(out, qualifiers); } else { out.insert(&BadType::instance); } } }
void ExportPass::ConstructModuleSymbols() { CProcedureType* originalType = dynamic_cast<CProcedureType*>(originalProcedure->get_procedure_symbol()->get_type()) ; assert(originalType != NULL) ; // The original type takes and returns a struct. We need to change this // to a list of arguments. VoidType* newReturnType = create_void_type(theEnv, IInteger(0), 0) ; constructedType = create_c_procedure_type(theEnv, newReturnType, false, // has varargs true, // arguments_known 0, // bit alignment LString("ConstructedType")) ; StructType* returnType = dynamic_cast<StructType*>(originalType->get_result_type()) ; assert(returnType != NULL) ; SymbolTable* structSymTab = returnType->get_group_symbol_table() ; assert(structSymTab != NULL) ; for (int i = 0 ; i < structSymTab->get_symbol_table_object_count() ; ++i) { VariableSymbol* nextVariable = dynamic_cast<VariableSymbol*>(structSymTab->get_symbol_table_object(i)); if (nextVariable != NULL) { // Check to see if this is an output or not QualifiedType* cloneType ; DataType* cloneBase = dynamic_cast<DataType*>(nextVariable->get_type()->get_base_type()->deep_clone()) ; assert(cloneBase != NULL) ; cloneType = create_qualified_type(theEnv, cloneBase) ; if (nextVariable->lookup_annote_by_name("Output") != NULL) { cloneType->append_annote(create_brick_annote(theEnv, "Output")) ; // Why doesn't this stick around? } constructedType->append_argument(cloneType) ; } } constructedSymbol = create_procedure_symbol(theEnv, constructedType, originalProcedure->get_procedure_symbol()->get_name()) ; constructedSymbol->set_definition(NULL) ; }
GenRet ArgSymbol::codegen() { GenInfo* info = gGenInfo; FILE* outfile = info->cfile; GenRet ret; if( outfile ) { QualifiedType qt = qualType(); ret.c = '&'; ret.c += cname; ret.isLVPtr = GEN_PTR; if (qt.isRef() && !qt.isRefType()) ret.chplType = getOrMakeRefTypeDuringCodegen(typeInfo()); else if (qt.isWideRef() && !qt.isWideRefType()) { Type* refType = getOrMakeRefTypeDuringCodegen(typeInfo()); ret.chplType = getOrMakeWideTypeDuringCodegen(refType); } /* // BHARSH TODO: Is this still necessary? if (q.isRef() && !q.isRefType()) { ret.c = cname; ret.isLVPtr = GEN_PTR; } else if(q.isWideRef() && !q.isWideRefType()) { ret.c = cname; ret.isLVPtr = GEN_WIDE_PTR; } else { ret.c = '&'; ret.c += cname; ret.isLVPtr = GEN_PTR; } */ } else { #ifdef HAVE_LLVM ret = info->lvt->getValue(cname); #endif } // BHARSH TODO: Is this still necessary? //if( requiresCPtr() ) { // // Don't try to use chplType. // ret.chplType = NULL; // ret = codegenLocalDeref(ret); //} //ret.chplType = this->type; return ret; }
ConversionRank CallCandidate::updateConversionRank() { conversionRank_ = IdenticalTypes; conversionCount_ = 0; size_t argCount = callExpr_->argCount(); for (size_t argIndex = 0; argIndex < argCount; ++argIndex) { Expr * argExpr = callExpr_->arg(argIndex); QualifiedType paramType = this->paramType(argIndex); combineConversionRanks(TypeConversion::check(argExpr, paramType, TypeConversion::COERCE)); } QualifiedType expectedReturnType = callExpr_->expectedReturnType(); if (!expectedReturnType.isNull() && callExpr_->exprType() != Expr::Construct) { AnalyzerBase::analyzeType(resultType_, Task_PrepTypeComparison); combineConversionRanks( TypeConversion::check(resultType_, expectedReturnType, TypeConversion::COERCE)); } // If there are explicit specializations, then check those too. // Note that these must be an exact match. if (spCandidate_ != NULL) { combineConversionRanks(spCandidate_->updateConversionRank()); } if (method_ != NULL && !method_->checkMutableSelf(base_)) { combineConversionRanks(QualifierLoss); } #if 0 if (typeArgs_ != NULL) { size_t typeArgCount = typeArgs_->size(); for (size_t i = 0; i < typeArgCount; ++i) { const Type * typeArg = (*typeArgs_)[i]; const Type * typeParam = (*typeParams_)[i]; ConversionRank rank = typeParam->canConvert(typeArg); if (rank < IdenticalTypes) { conversionRank_ = Incompatible; break; } } } #endif return conversionRank_; }
void ReferenceCleanupPass::CleanupCall(CallStatement* c) { assert(procDef != NULL) ; assert(c != NULL) ; // We only need to clean up module calls. If they are built in // functions, like boolsel, we don't want to do this. if (IsBuiltIn(c)) { return ; } // Go through the arguments and see if any of them are load variable // expressions to a reference typed variable, and replace those with // symbol address expressions for (unsigned int i = 0 ; i < c->get_argument_count() ; ++i) { Expression* currentArg = c->get_argument(i) ; LoadVariableExpression* currentLoadVar = dynamic_cast<LoadVariableExpression*>(currentArg) ; if (currentLoadVar != NULL) { VariableSymbol* currentVar = currentLoadVar->get_source() ; DataType* varType = currentVar->get_type()->get_base_type() ; ReferenceType* refType = dynamic_cast<ReferenceType*>(varType) ; if (refType != NULL) { QualifiedType* internalType = dynamic_cast<QualifiedType*>(refType->get_reference_type()) ; assert(internalType != NULL) ; // currentVar->set_type(internalType) ; SymbolAddressExpression* symAddrExp = create_symbol_address_expression(theEnv, internalType->get_base_type(), currentVar) ; if (currentLoadVar->lookup_annote_by_name("UndefinedPath") != NULL) { symAddrExp->append_annote(create_brick_annote(theEnv, "UndefinedPath")) ; } currentLoadVar->get_parent()->replace(currentLoadVar, symAddrExp) ; } } } }
void CallCandidate::reportConversionErrors() { diag.info(method_) << Format_Type << method_ << " [" << conversionRank_ << "]"; size_t argCount = callExpr_->argCount(); for (size_t argIndex = 0; argIndex < argCount; ++argIndex) { Expr * argExpr = callExpr_->arg(argIndex); QualifiedType paramType = this->paramType(argIndex); ConversionRank rank = TypeConversion::check(argExpr, paramType, TypeConversion::COERCE); if (isConversionWarning(rank)) { diag.indent(); diag.info(callExpr_) << compatibilityError(rank) << Format_Dealias << " converting argument " << argIndex << " from '" << argExpr->type() << "' to '" << paramType << "'."; diag.unindent(); } } QualifiedType expectedReturnType = callExpr_->expectedReturnType(); if (!expectedReturnType.isNull() && callExpr_->exprType() != Expr::Construct) { AnalyzerBase::analyzeType(resultType_, Task_PrepTypeComparison); ConversionRank rank = TypeConversion::check( resultType_, expectedReturnType, TypeConversion::COERCE); if (isConversionWarning(rank)) { diag.indent(); diag.info(callExpr_) << compatibilityError(rank) << Format_Dealias << " converting return value from '" << resultType_ << "' to '" << expectedReturnType << "'."; diag.unindent(); } } // If there are explicit specializations, then check those too. // Note that these must be an exact match. if (spCandidate_ != NULL) { spCandidate_->reportConversionErrors(); } if (method_ != NULL && !method_->checkMutableSelf(base_)) { diag.indent(); diag.info(callExpr_) << "Non-readonly method with a readonly 'self' argument"; diag.unindent(); } }
// Turn an reference pointer into an array reference expression void ReferenceCleanupPass::CleanupArrayStore(StoreStatement* s) { assert(s != NULL) ; // Check to see if the destination is a reference variable Expression* destination = s->get_destination_address() ; VariableSymbol* storedVariable = FindVariable(destination) ; if (storedVariable == NULL) { return ; } if (dynamic_cast<ReferenceType*>(storedVariable->get_type()->get_base_type())) { // Can I just change the type? Pointer conversion should take care of it // then, but I'll have to annotate it ReferenceType* refType = dynamic_cast<ReferenceType*>(storedVariable->get_type()->get_base_type()) ; QualifiedType* internalType = dynamic_cast<QualifiedType*>(refType->get_reference_type()) ; assert(internalType != NULL) ; DataType* internalType2 = internalType->get_base_type() ; QualifiedType* qualType = storedVariable->get_type() ; qualType->set_base_type(NULL) ; refType->set_parent(NULL) ; internalType->set_parent(NULL) ; refType->set_reference_type(NULL) ; qualType->set_base_type(internalType2) ; } }
bool ConstantArrayPropagationPass::ValidSymbol(VariableSymbol* var) { assert(var != NULL) ; // The variable should be an array type and have the const qualifier. if (dynamic_cast<ArrayType*>(var->get_type()->get_base_type()) == NULL) { return false ; } QualifiedType* qualType = var->get_type() ; while (dynamic_cast<ArrayType*>(qualType->get_base_type()) != NULL) { ArrayType* array = dynamic_cast<ArrayType*>(qualType->get_base_type()) ; qualType = array->get_element_type() ; } assert(qualType != NULL) ; for (int i = 0 ; i < qualType->get_qualification_count(); ++i) { if (qualType->get_qualification(i) == LString("const")) { return true ; } } return false ; }
static Type* getArgSymbolCodegenType(ArgSymbol* arg) { QualifiedType q = arg->qualType(); Type* useType = q.type(); if (q.isRef() && !q.isRefType()) useType = getOrMakeRefTypeDuringCodegen(useType); if (q.isWideRef() && !q.isWideRefType()) { Type* refType = getOrMakeRefTypeDuringCodegen(useType); useType = getOrMakeWideTypeDuringCodegen(refType); } return useType; }
int LexicalTypeOrdering::compare(const QualifiedType & t0, const QualifiedType & t1) { int result = compare(t0.unqualified(), t1.unqualified()); if (result != 0) { return result; } if (t0.qualifiers() < t1.qualifiers()) { return -1; } else if (t0.qualifiers() > t1.qualifiers()) { return 1; } else { return 0; } }
DataType* ExportPass::CloneDataType(DataType* t) { assert(t != NULL) ; PointerType* pointerClone = dynamic_cast<PointerType*>(t) ; ReferenceType* referenceClone = dynamic_cast<ReferenceType*>(t) ; ArrayType* arrayClone = dynamic_cast<ArrayType*>(t) ; if (pointerClone != NULL) { QualifiedType* refType = dynamic_cast<QualifiedType*>(pointerClone->get_reference_type()) ; assert(refType != NULL) ; DataType* cloneType = CloneDataType(refType->get_base_type()) ; assert(cloneType != NULL) ; return create_pointer_type(theEnv, IInteger(32), 0, create_qualified_type(theEnv, cloneType)) ; } if (referenceClone != NULL) { QualifiedType* refType = dynamic_cast<QualifiedType*>(referenceClone->get_reference_type()) ; assert(refType != NULL) ; DataType* clonedType = CloneDataType(refType->get_base_type()) ; return create_reference_type(theEnv, IInteger(32), 0, create_qualified_type(theEnv, clonedType)) ; } if (arrayClone != NULL) { QualifiedType* elementType = arrayClone->get_element_type() ; DataType* internalType = CloneDataType(elementType->get_base_type()) ; QualifiedType* finalQual = create_qualified_type(theEnv, internalType) ; return create_pointer_type(theEnv, IInteger(32), 0, finalQual) ; } return dynamic_cast<DataType*>(t->deep_clone()) ; }
void DismantleStructuredReturns::do_file_set_block( FileSetBlock* file_set_block ) { suif_map<CProcedureType *,QualifiedType *> type_map; list<ArrayReferenceExpression*> ref_exprs; SuifEnv *env = 0; TypeBuilder *tb = 0; VoidType *vt = 0; for (Iter<ProcedureSymbol> iter = object_iterator<ProcedureSymbol>(file_set_block); iter.is_valid(); iter.next()) { ProcedureSymbol *sym = &iter.current(); Type *type = sym->get_type(); if (!is_kind_of<CProcedureType>(type)) continue; CProcedureType *cp_type = to<CProcedureType>(type); type = cp_type->get_result_type(); if (!env) { env = type->get_suif_env(); tb = (TypeBuilder*) env->get_object_factory(TypeBuilder::get_class_name()); vt = tb->get_void_type(); } suif_map<CProcedureType *,QualifiedType *>::iterator t_iter = type_map.find(cp_type); QualifiedType *qtype; if (t_iter == type_map.end()) { if (!is_kind_of<GroupType>(type) && !is_kind_of<ArrayType>(type)) continue; qtype = tb->get_qualified_type( tb->get_pointer_type(to<DataType>(type))); cp_type->set_result_type(vt); cp_type->insert_argument(0,qtype); type_map.enter_value(cp_type,qtype); } else { qtype = (*t_iter).second; } ProcedureDefinition *def = sym->get_definition(); if (!def) continue; ParameterSymbol *par = create_parameter_symbol(env,qtype); def->get_symbol_table()->append_symbol_table_object(par); def->insert_formal_parameter(0,par); // Convert all returns into assigned and returns for (Iter<ReturnStatement> ret_iter = object_iterator<ReturnStatement>(def->get_body()); ret_iter.is_valid(); ret_iter.next()) { ReturnStatement *ret = &ret_iter.current(); Expression *retval = ret->get_return_value(); ret->set_return_value(0); retval->set_parent(0); insert_statement_before(ret, create_store_statement(env,retval,create_var_use(par))); } } // Change all calls to the new form for (Iter<CallStatement> cs_iter = object_iterator<CallStatement>(file_set_block); cs_iter.is_valid(); cs_iter.next()) { CallStatement *call = &cs_iter.current(); Type *type = call->get_callee_address()->get_result_type(); Type *p_type = tb->unqualify_type(to<PointerType>(type)->get_reference_type()); if (!is_kind_of<PointerType>(p_type)) continue; p_type = tb->unqualify_type(to<PointerType>(p_type)->get_reference_type()); if (!is_kind_of<CProcedureType>(p_type)) continue; CProcedureType *cp_type = to<CProcedureType>(p_type); suif_map<CProcedureType *,QualifiedType *>::iterator t_iter = type_map.find(cp_type); if (t_iter == type_map.end()) continue; QualifiedType *qtype = (*t_iter).second; DataType *var_type = to<DataType>(tb->unqualify_type(to<PointerType>(qtype->get_base_type()) ->get_reference_type())); VariableSymbol *var = new_anonymous_variable(env,call,tb->get_qualified_type(var_type)); Expression *exp = create_symbol_address_expression( env, tb->get_pointer_type(var_type), var); call->insert_argument(0,exp); call->set_destination(0); } for (Iter<CallExpression> ce_iter = object_iterator<CallExpression>(file_set_block); ce_iter.is_valid(); ce_iter.next()) { CallExpression *call = &ce_iter.current(); Type *type = call->get_callee_address()->get_result_type(); Type *p_type = tb->unqualify_type(to<PointerType>(type)->get_reference_type()); if (!is_kind_of<PointerType>(p_type)) continue; p_type = tb->unqualify_type(to<PointerType>(p_type)->get_reference_type()); if (!is_kind_of<CProcedureType>(p_type)) continue; CProcedureType *cp_type = to<CProcedureType>(p_type); ; suif_map<CProcedureType *,QualifiedType *>::iterator t_iter = type_map.find(cp_type); if (t_iter == type_map.end()) continue; QualifiedType *qtype = (*t_iter).second; DataType *var_type = to<DataType>(tb->unqualify_type(to<PointerType>(qtype->get_base_type()) ->get_reference_type())); VariableSymbol *var = new_anonymous_variable(env,call,tb->get_qualified_type(var_type)); Expression *exp = create_symbol_address_expression( env, tb->get_pointer_type(var_type), var); call->insert_argument(0,exp); Statement *loc = get_expression_owner(call); call->get_parent()->replace(call,create_var_use(var)); call->set_parent(0); suif_assert(vt != 0); call->set_result_type(vt); EvalStatement *es = create_eval_statement(env); insert_statement_before(loc,es); // Would be better to turn this into a call statement es->append_expression(call); } }
static QualifiedType returnInfoArrayIndex(CallExpr* call) { QualifiedType tmp = returnInfoArrayIndexValue(call); return QualifiedType(tmp.type()->refType, QUAL_REF); }
static QualifiedType returnInfoFirstDeref(CallExpr* call) { QualifiedType tmp = call->get(1)->qualType(); Type* type = tmp.type()->getValType(); return QualifiedType(type, QUAL_VAL); }
void ExportPass::ConstructSystemSymbols() { ProcedureSymbol* originalSymbol = originalProcedure->get_procedure_symbol() ; assert(originalSymbol != NULL) ; CProcedureType* originalType = dynamic_cast<CProcedureType*>(originalSymbol->get_type()) ; assert(originalType != NULL) ; constructedType = create_c_procedure_type(theEnv, dynamic_cast<DataType*>(originalType->get_result_type()->deep_clone()), false, // has variable arguments false, // arguments known 0) ; // bit alignment // The system has been written in one of two ways, either the old // way where there are no arguments, or the new way where everything // is put into the arguments. if (originalType->get_argument_count() > 0) { for (int i = 0 ; i < originalType->get_argument_count() ; ++i) { QualifiedType* originalArgument = originalType->get_argument(i) ; DataType* originalBase = originalArgument->get_base_type() ; DataType* constructedBase = CloneDataType(originalBase) ; QualifiedType* constructedArgument = create_qualified_type(theEnv, constructedBase) ; constructedType->append_argument(constructedArgument) ; // Go through the symbol table and find the parameter symbol // that matches the parameter number, and check to see if it // is an output or not... SymbolTable* symTab = originalProcedure->get_symbol_table() ; ParameterSymbol* correspondingSymbol = NULL ; for (int j = 0 ; j < symTab->get_symbol_table_object_count() ; ++j) { ParameterSymbol* currentSym = dynamic_cast<ParameterSymbol*>(symTab->get_symbol_table_object(j)) ; if (currentSym != NULL) { BrickAnnote* orderAnnote = dynamic_cast<BrickAnnote*>(currentSym->lookup_annote_by_name("ParameterOrder")) ; assert(orderAnnote != NULL) ; IntegerBrick* orderBrick = dynamic_cast<IntegerBrick*>(orderAnnote->get_brick(0)) ; assert(orderBrick != NULL) ; if (orderBrick->get_value().c_int() == i) { correspondingSymbol = currentSym ; break ; } } } if (correspondingSymbol != NULL) { if (correspondingSymbol->lookup_annote_by_name("OutputScalar") != NULL || correspondingSymbol->lookup_annote_by_name("OutputVariable") != NULL || correspondingSymbol->lookup_annote_by_name("OutputFifo") != NULL) { constructedArgument->append_annote(create_brick_annote(theEnv, "Output")) ; } } // if (dynamic_cast<ReferenceType*>(originalBase) != NULL) //{ // constructedArgument->append_annote(create_brick_annote(theEnv, // "Output")) ; // } } } else { SymbolTable* symTab = originalProcedure->get_symbol_table() ; assert(symTab != NULL) ; list<VariableSymbol*> inputScalars ; list<VariableSymbol*> inputFifos ; list<VariableSymbol*> outputScalars ; list<VariableSymbol*> outputFifos ; for (int i = 0 ; i < symTab->get_symbol_table_object_count() ; ++i) { VariableSymbol* currentVar = dynamic_cast<VariableSymbol*>(symTab->get_symbol_table_object(i)) ; if (currentVar != NULL && currentVar->lookup_annote_by_name("InputScalar") != NULL && currentVar->lookup_annote_by_name("TemporalFeedback") == NULL && currentVar->lookup_annote_by_name("NormalFeedback") == NULL && currentVar->lookup_annote_by_name("DebugRegister") == NULL) { inputScalars.push_back(currentVar) ; } if (currentVar != NULL && currentVar->lookup_annote_by_name("InputFifo") != NULL) { inputFifos.push_back(currentVar) ; } if (currentVar != NULL && currentVar->lookup_annote_by_name("OutputVariable") != NULL && currentVar->lookup_annote_by_name("Dummy") == NULL && currentVar->lookup_annote_by_name("FeedbackSource") == NULL) { outputScalars.push_back(currentVar) ; } if (currentVar != NULL && currentVar->lookup_annote_by_name("OutputFifo") != NULL) { outputFifos.push_back(currentVar) ; } } // Add the types of the input scalars, then the input fifos, // then the output scalars, and finally the output fifos. list<VariableSymbol*>::iterator varIter = inputScalars.begin() ; while (varIter != inputScalars.end()) { QualifiedType* originalQual = (*varIter)->get_type() ; assert(originalQual != NULL) ; DataType* originalBase = originalQual->get_base_type() ; assert(originalBase != NULL) ; DataType* constructedBase = dynamic_cast<DataType*>(originalBase->deep_clone()) ; QualifiedType* constructedQual = create_qualified_type(theEnv, constructedBase) ; constructedType->append_argument(constructedQual) ; ++varIter ; } varIter = inputFifos.begin() ; while (varIter != inputFifos.end()) { QualifiedType* originalQual = (*varIter)->get_type() ; assert(originalQual != NULL) ; DataType* originalBase = originalQual->get_base_type() ; assert(originalBase != NULL) ; // Fifos will have pointer types or reference types. A // simple deep clone will not suffice, I need to build up a // new type from the bottom up. DataType* constructedBase = CloneDataType(originalBase) ; assert(constructedBase != NULL) ; QualifiedType* constructedQual = create_qualified_type(theEnv, constructedBase) ; assert(constructedBase != NULL) ; assert(constructedType != NULL) ; constructedType->append_argument(constructedQual) ; ++varIter ; } varIter = outputScalars.begin() ; while (varIter != outputScalars.end()) { QualifiedType* originalQual = (*varIter)->get_type() ; DataType* originalBase = originalQual->get_base_type() ; DataType* constructedBase = CloneDataType(originalBase) ; QualifiedType* constructedQual = create_qualified_type(theEnv, constructedBase) ; constructedQual->append_annote(create_brick_annote(theEnv, "Output")) ; constructedType->append_argument(constructedQual) ; ++varIter ; } varIter = outputFifos.begin() ; while (varIter != outputFifos.end()) { QualifiedType* originalQual = (*varIter)->get_type() ; assert(originalQual != NULL) ; DataType* originalBase = originalQual->get_base_type() ; assert(originalBase != NULL) ; DataType* constructedBase = CloneDataType(originalBase) ; assert(constructedBase != NULL) ; QualifiedType* constructedQual = create_qualified_type(theEnv, constructedBase) ; assert(constructedQual != NULL) ; constructedQual->append_annote(create_brick_annote(theEnv, "Output")) ; assert(constructedType != NULL) ; constructedType->append_argument(constructedQual) ; ++varIter ; } } constructedSymbol = create_procedure_symbol(theEnv, constructedType, originalProcedure->get_procedure_symbol()->get_name()) ; }
// All of the array references expressions in the passed in the struct are // equivalent, so we can determine types of the original and use that // to create a new expression with which to replace everything. bool TransformUnrolledArraysPass::ReplaceNDReference(EquivalentReferences* a) { assert(a != NULL) ; assert(a->original != NULL) ; // Check to see if the reference at this stage is a constant or not IntConstant* constantIndex = dynamic_cast<IntConstant*>(a->original->get_index()) ; if (constantIndex == NULL) { // There was no replacement made return false ; } Expression* baseAddress = a->original->get_base_array_address() ; assert(baseAddress != NULL) ; assert(constantIndex != NULL) ; // Create a replacement expression for this value. This will either // be another array reference expression or a single variable. Expression* replacementExp = NULL ; // QualifiedType* elementType = GetQualifiedTypeOfElement(a->original) ; VariableSymbol* originalSymbol = GetArrayVariable(a->original) ; assert(originalSymbol != NULL) ; LString replacementName = GetReplacementName(originalSymbol->get_name(), constantIndex->get_value().c_int()) ; int dimensionality = GetDimensionality(a->original) ; QualifiedType* elementType = originalSymbol->get_type() ; while (dynamic_cast<ArrayType*>(elementType->get_base_type()) != NULL) { elementType = dynamic_cast<ArrayType*>(elementType->get_base_type())->get_element_type() ; } // There is a special case for one dimensional arrays as opposed to all // other dimensional arrays. It only should happen if we are truly // replacing an array with a one dimensional array. if (dimensionality == 1 && dynamic_cast<ArrayReferenceExpression*>(a->original->get_parent())==NULL) { VariableSymbol* replacementVar = create_variable_symbol(theEnv, GetQualifiedTypeOfElement(a->original), TempName(replacementName)) ; procDef->get_symbol_table()->append_symbol_table_object(replacementVar) ; replacementExp = create_load_variable_expression(theEnv, elementType->get_base_type(), replacementVar) ; } else { // Create a new array with one less dimension. This requires a new // array type. ArrayType* varType = dynamic_cast<ArrayType*>(originalSymbol->get_type()->get_base_type()) ; assert(varType != NULL) ; ArrayType* replacementArrayType = create_array_type(theEnv, varType->get_element_type()->get_base_type()->get_bit_size(), 0, // bit alignment OneLessDimension(originalSymbol->get_type(), dimensionality), dynamic_cast<Expression*>(varType->get_lower_bound()->deep_clone()), dynamic_cast<Expression*>(varType->get_upper_bound()->deep_clone()), TempName(varType->get_name())) ; procDef->get_symbol_table()->append_symbol_table_object(replacementArrayType) ; VariableSymbol* replacementArraySymbol = create_variable_symbol(theEnv, create_qualified_type(theEnv, replacementArrayType, TempName(LString("qualType"))), TempName(replacementName)) ; procDef->get_symbol_table()->append_symbol_table_object(replacementArraySymbol) ; // Create a new symbol address expression for this variable symbol SymbolAddressExpression* replacementAddrExp = create_symbol_address_expression(theEnv, replacementArrayType, replacementArraySymbol) ; // Now, replace the symbol address expression in the base // array address with this symbol. ReplaceSymbol(a->original, replacementAddrExp) ; // And replace this reference with the base array address. replacementExp = a->original->get_base_array_address() ; a->original->set_base_array_address(NULL) ; replacementExp->set_parent(NULL) ; } // Replace all of the equivalent expressions with the newly generated // replacement expression. assert(replacementExp != NULL) ; a->original->get_parent()->replace(a->original, replacementExp) ; // ReplaceChildExpression(a->original->get_parent(), // a->original, // replacementExp) ; list<ArrayReferenceExpression*>::iterator equivIter = a->allEquivalent.begin() ; while (equivIter != a->allEquivalent.end()) { (*equivIter)->get_parent()->replace((*equivIter), dynamic_cast<Expression*>(replacementExp->deep_clone())) ; // ReplaceChildExpression((*equivIter)->get_parent(), // (*equivIter), // dynamic_cast<Expression*>(replacementExp->deep_clone())) ; ++equivIter ; } return true ; }
// Do a sort of garbage collection. Take all of the types that we want to // delete and collect them. If there are no uses of them after this function // has finished, then remove them. void RemoveModulePass::RemoveProcedure(ProcedureSymbol* p) { assert(repository != NULL) ; list<Type*> usedTypes ; if (p == NULL) { return ; } // There should be no definition, but just in case remove it ProcedureDefinition* defToRemove = p->get_definition() ; p->set_definition(NULL) ; if (defToRemove != NULL) { delete defToRemove ; } // Clear out all of the values associated with the procedure type CProcedureType* procType = dynamic_cast<CProcedureType*>(p->get_type()) ; assert(procType != NULL) ; DataType* returnTypeToRemove = procType->get_result_type() ; procType->set_result_type(NULL) ; if (returnTypeToRemove != NULL) { usedTypes.push_back(returnTypeToRemove) ; } while (procType->get_argument_count() > 0) { QualifiedType* currentArg = procType->get_argument(0) ; procType->remove_argument(0) ; if (!InList(usedTypes, currentArg)) { usedTypes.push_back(currentArg) ; } } SymbolTable* symTab = repository->get_external_symbol_table() ; p->set_type(NULL) ; symTab->remove_symbol_table_object(procType) ; delete procType ; symTab->remove_symbol_table_object(p) ; delete p ; // Now, go through each used type and see if it is used anywhere list<Type*>::iterator typeIter = usedTypes.begin() ; while (typeIter != usedTypes.end()) { bool removeMe = true ; for (int i = 0 ; i < symTab->get_symbol_table_object_count() ; ++i) { CProcedureType* currentType = dynamic_cast<CProcedureType*>(symTab->get_symbol_table_object(i)) ; if (currentType != NULL) { if (IsUsed(*typeIter, currentType)) { removeMe = false ; break ; } } } if (removeMe) { if ((*typeIter)->lookup_annote_by_name("Output") != NULL) { delete (*typeIter)->remove_annote_by_name("Output") ; } QualifiedType* q = dynamic_cast<QualifiedType*>(*typeIter) ; DataType* d = dynamic_cast<DataType*>(*typeIter) ; if (q != NULL) { DataType* internalD = q->get_base_type() ; q->set_base_type(NULL) ; symTab->remove_symbol_table_object(internalD) ; symTab->remove_symbol_table_object(q) ; delete internalD ; delete q ; } else if (d != NULL) { symTab->remove_symbol_table_object(d) ; delete d ; } else { assert(0 && "Trying to remove something weird...") ; } } ++typeIter ; } }
bool FunctionMergePass::areTypesCompatible(QualifiedType from, QualifiedType to) { return areTypesCompatible(from.unqualified(), to.unqualified()); }
void TransformSystemsToModules::Transform() { assert(procDef != NULL) ; // Collect all the input scalars and output scalars list<VariableSymbol*> ports ; SymbolTable* procSymTab = procDef->get_symbol_table() ; bool foundInputs = false ; bool foundOutputs = false ; for (int i = 0 ; i < procSymTab->get_symbol_table_object_count() ; ++i) { SymbolTableObject* nextObject = procSymTab->get_symbol_table_object(i) ; if (nextObject->lookup_annote_by_name("InputScalar") != NULL) { VariableSymbol* toConvert = dynamic_cast<VariableSymbol*>(nextObject) ; assert(toConvert != NULL) ; LString inputName = toConvert->get_name() ; inputName = inputName + "_in" ; toConvert->set_name(inputName) ; ports.push_back(toConvert) ; foundInputs = true ; } if (nextObject->lookup_annote_by_name("OutputVariable") != NULL) { VariableSymbol* toConvert = dynamic_cast<VariableSymbol*>(nextObject) ; assert(toConvert != NULL) ; LString outputName = toConvert->get_name() ; outputName = outputName + "_out" ; toConvert->set_name(outputName) ; ports.push_back(toConvert) ; foundOutputs = true ; } } assert(foundInputs && "Could not identify inputs. Were they removed via optimizations?") ; assert(foundOutputs && "Could not identify outputs. Were they removed via optimizations?") ; // Determine the bit size and add everything to a new symbol table int bitSize = 0 ; GroupSymbolTable* structTable = create_group_symbol_table(theEnv, procDef->get_symbol_table()) ; std::map<VariableSymbol*, FieldSymbol*> replacementFields ; bool portsRemoved = false ; // If this was actually a new style module, we should make sure to // put these in the correct order. if (isModule(procDef)) { // Go through the original symbol table and remove any parameter // symbols that originally existed SymbolTable* originalSymTab = procDef->get_symbol_table() ; Iter<SymbolTableObject*> originalIter = originalSymTab->get_symbol_table_object_iterator() ; while (originalIter.is_valid()) { SymbolTableObject* currentObj = originalIter.current() ; originalIter.next() ; if (dynamic_cast<ParameterSymbol*>(currentObj) != NULL) { originalSymTab->remove_symbol_table_object(currentObj) ; } } portsRemoved = true ; // Sort the variable symbols in parameter order. This is just an // insertion sort, so it could be done faster. list<VariableSymbol*> sortedPorts ; for (int i = 0 ; i < ports.size() ; ++i) { list<VariableSymbol*>::iterator portIter = ports.begin() ; while (portIter != ports.end()) { BrickAnnote* orderAnnote = dynamic_cast<BrickAnnote*>((*portIter)-> lookup_annote_by_name("ParameterOrder")) ; if (orderAnnote == NULL) { ++portIter ; continue ; } IntegerBrick* orderBrick = dynamic_cast<IntegerBrick*>(orderAnnote->get_brick(0)) ; assert(orderBrick != NULL) ; if (orderBrick->get_value().c_int() == i) { sortedPorts.push_back(*portIter) ; break ; } ++portIter ; } } if (sortedPorts.size() != ports.size()) { OutputWarning("Warning! Analysis detected some input scalars not in" " the parameter list") ; } // Replace ports with sortedPorts ports = sortedPorts ; } list<VariableSymbol*>::iterator portIter = ports.begin() ; while (portIter != ports.end()) { bitSize += (*portIter)->get_type()->get_base_type()->get_bit_size().c_int() ; LString dupeName = (*portIter)->get_name() ; // Create offset expression: IntConstant* offset = create_int_constant(theEnv, create_data_type(theEnv, IInteger(32), 0), IInteger(bitSize)) ; QualifiedType* dupeType = (*portIter)->get_type() ; // Deal with the case where reference types were passed in ReferenceType* refType = dynamic_cast<ReferenceType*>(dupeType->get_base_type()) ; while (refType != NULL) { dupeType = dynamic_cast<QualifiedType*>(refType->get_reference_type()) ; assert(dupeType != NULL) ; refType = dynamic_cast<ReferenceType*>(dupeType->get_base_type()) ; } // Create a new variable symbol clone FieldSymbol* dupe = create_field_symbol(theEnv, dupeType, offset, dupeName) ; structTable->append_symbol_table_object(dupe) ; // Make the connection with the duplicated symbol replacementFields[(*portIter)] = dupe ; // Remove the original variable symbol from the procedure definition // symbol table. if (!portsRemoved) { procDef->get_symbol_table()->remove_symbol_table_object(*portIter) ; } ++portIter ; } assert(bitSize != 0); StructType* moduleStruct = create_struct_type(theEnv, IInteger(bitSize), 0, // bit_alignment TempName(procDef->get_procedure_symbol()->get_name()), 0, // is_complete structTable) ; Iter<FileBlock*> fBlocks = theEnv->get_file_set_block()->get_file_block_iterator() ; assert(fBlocks.is_valid()) ; (fBlocks.current())->get_symbol_table()->append_symbol_table_object(moduleStruct) ; // This is commented out because it is in the file state block //procDef->get_symbol_table()->append_symbol_table_object(moduleStruct) ; QualifiedType* qualifiedModuleStruct = create_qualified_type(theEnv, moduleStruct, TempName(LString("qualifiedModuleStruct"))) ; procDef->get_symbol_table()->append_symbol_table_object(qualifiedModuleStruct) ; // Create an instance of this type and add it to the symbol table. ParameterSymbol* structInstance = create_parameter_symbol(theEnv, qualifiedModuleStruct, TempName(LString("structInstance"))) ; procDef->get_symbol_table()->append_symbol_table_object(structInstance) ; // Now, set up the procedure symbol to take the struct and return the // struct. assert(procDef != NULL) ; ProcedureSymbol* procSym = procDef->get_procedure_symbol() ; assert(procSym != NULL) ; ProcedureType* procType = procSym->get_type() ; assert(procType != NULL) ; CProcedureType* cProcType = dynamic_cast<CProcedureType*>(procType) ; assert(cProcType != NULL) ; // Instead of appending the struct argument, we need to replace all of the // arguments with the struct. while (cProcType->get_argument_count() > 0) { cProcType->remove_argument(0) ; } cProcType->set_result_type(moduleStruct) ; cProcType->append_argument(qualifiedModuleStruct) ; // Now go through all load variable expressions and replace them all with // field symbol values if appropriate list<LoadVariableExpression*>* allLoads = collect_objects<LoadVariableExpression>(procDef->get_body()) ; list<LoadVariableExpression*>::iterator loadIter = allLoads->begin() ; while (loadIter != allLoads->end()) { VariableSymbol* currentVariable = (*loadIter)->get_source() ; if (replacementFields.find(currentVariable) != replacementFields.end()) { (*loadIter)->set_source(replacementFields[currentVariable]) ; } ++loadIter ; } delete allLoads ; // Also replace all of the definitions with the field symbol list<StoreVariableStatement*>* allStoreVars = collect_objects<StoreVariableStatement>(procDef->get_body()) ; list<StoreVariableStatement*>::iterator storeVarIter = allStoreVars->begin(); while (storeVarIter != allStoreVars->end()) { VariableSymbol* currentDest = (*storeVarIter)->get_destination() ; if (replacementFields.find(currentDest) != replacementFields.end()) { (*storeVarIter)->set_destination(replacementFields[currentDest]) ; } ++storeVarIter ; } delete allStoreVars ; list<SymbolAddressExpression*>* allSymAddr = collect_objects<SymbolAddressExpression>(procDef->get_body()) ; list<SymbolAddressExpression*>::iterator symAddrIter = allSymAddr->begin() ; while (symAddrIter != allSymAddr->end()) { VariableSymbol* currentVar = dynamic_cast<VariableSymbol*>((*symAddrIter)->get_addressed_symbol()) ; if (currentVar != NULL && replacementFields.find(currentVar) != replacementFields.end()) { (*symAddrIter)->set_addressed_symbol(replacementFields[currentVar]) ; } ++symAddrIter ; } delete allSymAddr ; // One final for bool selects list<CallStatement*>* allCalls = collect_objects<CallStatement>(procDef->get_body()) ; list<CallStatement*>::iterator callIter = allCalls->begin() ; while(callIter != allCalls->end()) { VariableSymbol* currentVar = (*callIter)->get_destination() ; if (currentVar != NULL && replacementFields.find(currentVar) != replacementFields.end()) { (*callIter)->set_destination(replacementFields[currentVar]) ; } ++callIter ; } delete allCalls ; }
void VarSymbol::codegenDefC(bool global, bool isHeader) { GenInfo* info = gGenInfo; if (this->hasFlag(FLAG_EXTERN)) return; if (type == dtVoid) return; AggregateType* ct = toAggregateType(type); QualifiedType qt = qualType(); if (qt.isRef() && !qt.isRefType()) { Type* refType = getOrMakeRefTypeDuringCodegen(type); ct = toAggregateType(refType); } if (qt.isWideRef() && !qt.isWideRefType()) { Type* refType = getOrMakeRefTypeDuringCodegen(type); Type* wideType = getOrMakeWideTypeDuringCodegen(refType); ct = toAggregateType(wideType); } Type* useType = type; if (ct) useType = ct; std::string typestr = (this->hasFlag(FLAG_SUPER_CLASS) ? std::string(toAggregateType(useType)->classStructName(true)) : useType->codegen().c); // // a variable can be codegen'd as static if it is global and neither // exported nor external. // std::string str; if(fIncrementalCompilation) { bool addExtern = global && isHeader; str = (addExtern ? "extern " : "") + typestr + " " + cname; } else { bool isStatic = global && !hasFlag(FLAG_EXPORT) && !hasFlag(FLAG_EXTERN); str = (isStatic ? "static " : "") + typestr + " " + cname; } if (ct) { if (ct->isClass()) { if (isFnSymbol(defPoint->parentSymbol)) { str += " = NULL"; } } else if (ct->symbol->hasFlag(FLAG_WIDE_REF) || ct->symbol->hasFlag(FLAG_WIDE_CLASS)) { if (isFnSymbol(defPoint->parentSymbol)) { if (widePointersStruct) { // // CHPL_LOCALEID_T_INIT is #defined in the chpl-locale-model.h // file in the runtime, for the selected locale model. // str += " = {CHPL_LOCALEID_T_INIT, NULL}"; } else { str += " = ((wide_ptr_t) NULL)"; } } } } if (fGenIDS) str = idCommentTemp(this) + str; if (printCppLineno && !isHeader && !isTypeSymbol(defPoint->parentSymbol)) str = zlineToString(this) + str; info->cLocalDecls.push_back(str); }
GenRet VarSymbol::codegenVarSymbol(bool lhsInSetReference) { GenInfo* info = gGenInfo; FILE* outfile = info->cfile; GenRet ret; ret.chplType = typeInfo(); if( outfile ) { // dtString immediates don't actually codegen as immediates, we just use // them for param string functionality. if (immediate && ret.chplType != dtString) { ret.isLVPtr = GEN_VAL; if (immediate->const_kind == CONST_KIND_STRING) { ret.c += '"'; ret.c += immediate->v_string; ret.c += '"'; } else if (immediate->const_kind == NUM_KIND_BOOL) { std::string bstring = (immediate->bool_value())?"true":"false"; const char* castString = "("; switch (immediate->num_index) { case BOOL_SIZE_1: case BOOL_SIZE_SYS: case BOOL_SIZE_8: castString = "UINT8("; break; case BOOL_SIZE_16: castString = "UINT16("; break; case BOOL_SIZE_32: castString = "UINT32("; break; case BOOL_SIZE_64: castString = "UINT64("; break; default: INT_FATAL("Unexpected immediate->num_index: %d\n", immediate->num_index); } ret.c = castString + bstring + ")"; } else if (immediate->const_kind == NUM_KIND_INT) { int64_t iconst = immediate->int_value(); if (iconst == (1ll<<63)) { ret.c = "-INT64(9223372036854775807) - INT64(1)"; } else if (iconst <= -2147483648ll || iconst >= 2147483647ll) { ret.c = "INT64(" + int64_to_string(iconst) + ")"; } else { const char* castString = "("; switch (immediate->num_index) { case INT_SIZE_8: castString = "INT8("; break; case INT_SIZE_16: castString = "INT16("; break; case INT_SIZE_32: castString = "INT32("; break; case INT_SIZE_64: castString = "INT64("; break; default: INT_FATAL("Unexpected immediate->num_index: %d\n", immediate->num_index); } ret.c = castString + int64_to_string(iconst) + ")"; } } else if (immediate->const_kind == NUM_KIND_UINT) { uint64_t uconst = immediate->uint_value(); if( uconst <= (uint64_t) INT32_MAX ) { const char* castString = "("; switch (immediate->num_index) { case INT_SIZE_8: castString = "UINT8("; break; case INT_SIZE_16: castString = "UINT16("; break; case INT_SIZE_32: castString = "UINT32("; break; case INT_SIZE_64: castString = "UINT64("; break; default: INT_FATAL("Unexpected immediate->num_index: %d\n", immediate->num_index); } ret.c = castString + uint64_to_string(uconst) + ")"; } else { ret.c = "UINT64(" + uint64_to_string(uconst) + ")"; } } else { ret.c = cname; // in C, all floating point literals are (double) } } else { // not immediate // is it a constant extern? If it is, it might be for example // an enum or #define'd value, in which case taking the address // of it is simply nonsense. Therefore, we code generate // extern const symbols as GEN_VAL (ie not an lvalue). if( hasFlag(FLAG_CONST) && hasFlag(FLAG_EXTERN) ) { ret.isLVPtr = GEN_VAL; ret.c = cname; } else { QualifiedType qt = qualType(); if (lhsInSetReference) { ret.c = '&'; ret.c += cname; ret.isLVPtr = GEN_PTR; if (qt.isRef() && !qt.isRefType()) ret.chplType = getOrMakeRefTypeDuringCodegen(typeInfo()); else if (qt.isWideRef() && !qt.isWideRefType()) { Type* refType = getOrMakeRefTypeDuringCodegen(typeInfo()); ret.chplType = getOrMakeWideTypeDuringCodegen(refType); } } else { if (qt.isRef() && !qt.isRefType()) { ret.c = cname; ret.isLVPtr = GEN_PTR; } else if(qt.isWideRef() && !qt.isWideRefType()) { ret.c = cname; ret.isLVPtr = GEN_WIDE_PTR; } else { ret.c = '&'; ret.c += cname; ret.isLVPtr = GEN_PTR; } } } // Print string contents in a comment if developer mode // and savec is set. if (developer && 0 != strcmp(saveCDir, "") && immediate && ret.chplType == dtString && immediate->const_kind == CONST_KIND_STRING) { if (strstr(immediate->v_string, "/*") || strstr(immediate->v_string, "*/")) { // Don't emit comment b/c string contained comment character. } else { ret.c += " /* \""; ret.c += immediate->v_string; ret.c += "\" */"; } } } return ret; } else { #ifdef HAVE_LLVM // for LLVM // Handle extern type variables. if( hasFlag(FLAG_EXTERN) && isType() ) { // code generate the type. GenRet got = typeInfo(); return got; } // for nil, generate a void pointer of chplType dtNil // to allow LLVM pointer cast // e.g. T = ( (locale) (nil) ); // // We would just compare against dtNil, but in some cases // the code generator needs to assign e.g. // _ret:dtNil = nil if( typeInfo() == dtNil && 0 == strcmp(cname, "nil") ) { GenRet voidPtr; voidPtr.val = llvm::Constant::getNullValue(info->builder->getInt8PtrTy()); voidPtr.chplType = dtNil; return voidPtr; } if (typeInfo() == dtBool){ // since "true" and "false" are read into the LVT during ReadMacrosAction // they will generate an LLVM value of type i32 instead of i8 if (0 == strcmp(cname, "false")){ GenRet boolVal = new_UIntSymbol(0, INT_SIZE_8)->codegen(); return boolVal; } if (0 == strcmp(cname, "true")){ GenRet boolVal = new_UIntSymbol(1, INT_SIZE_8)->codegen(); return boolVal; } } if(!isImmediate()) { // check LVT for value GenRet got = info->lvt->getValue(cname); got.chplType = typeInfo(); if( got.val ) { return got; } } if(isImmediate()) { ret.isLVPtr = GEN_VAL; if(immediate->const_kind == CONST_KIND_STRING) { if(llvm::Value *value = info->module->getNamedGlobal(name)) { ret.val = value; ret.isLVPtr = GEN_PTR; return ret; } llvm::Value *constString = codegenImmediateLLVM(immediate); llvm::GlobalVariable *globalValue = llvm::cast<llvm::GlobalVariable>( info->module->getOrInsertGlobal (name, info->builder->getInt8PtrTy())); globalValue->setConstant(true); globalValue->setInitializer(llvm::cast<llvm::Constant>( info->builder->CreateConstInBoundsGEP2_32( #if HAVE_LLVM_VER >= 37 NULL, #endif constString, 0, 0))); ret.val = globalValue; ret.isLVPtr = GEN_PTR; } else { ret.val = codegenImmediateLLVM(immediate); } return ret; } if(std::string(cname) == "0") { // Chapel compiler should not make these. INT_FATAL(" zero value BOO "); return ret; } else if (std::string(cname) == "NULL") { GenRet voidPtr; voidPtr.val = llvm::Constant::getNullValue(info->builder->getInt8PtrTy()); voidPtr.chplType = typeInfo(); return voidPtr; } #endif } INT_FATAL("Could not code generate %s - " "perhaps it is a complex macro?", cname); return ret; }
Value * CodeGenerator::genCall(const tart::FnCallExpr* in) { const FunctionDefn * fn = in->function(); const FunctionType * fnType = fn->functionType(); bool saveIntermediateStackRoots = true; if (fn->isIntrinsic()) { return fn->intrinsic()->generate(*this, in); } size_t savedRootCount = rootStackSize(); ValueList args; fnType->irType(); // Need to know the irType for isStructReturn. Value * retVal = NULL; if (fnType->isStructReturn()) { DASSERT(in->exprType() != Expr::CtorCall); // Constructors have no return. retVal = builder_.CreateAlloca(fnType->returnType()->irType(), NULL, "sret"); args.push_back(retVal); } Value * selfArg = NULL; if (in->selfArg() != NULL) { Type::TypeClass selfTypeClass = in->selfArg()->type()->typeClass(); if (selfTypeClass == Type::Struct) { if (in->exprType() == Expr::CtorCall) { selfArg = genExpr(in->selfArg()); } else { selfArg = genLValueAddress(in->selfArg()); } } else { selfArg = genArgExpr(in->selfArg(), saveIntermediateStackRoots); } DASSERT_OBJ(selfArg != NULL, in->selfArg()); // Upcast the self argument type. if (fnType->selfParam() != NULL) { const Type * selfType = fnType->selfParam()->type().dealias().unqualified(); selfArg = genUpCastInstr(selfArg, in->selfArg()->type().unqualified(), selfType); } if (fn->storageClass() == Storage_Instance) { args.push_back(selfArg); } } const ExprList & inArgs = in->args(); for (ExprList::const_iterator it = inArgs.begin(); it != inArgs.end(); ++it) { const Expr * arg = *it; QualifiedType argType = arg->canonicalType(); Value * argVal = genArgExpr(arg, saveIntermediateStackRoots); if (argVal == NULL) { return NULL; } DASSERT_TYPE_EQ(in, argType->irParameterType(), argVal->getType()); args.push_back(argVal); } // Generate the function to call. Value * fnVal; if (in->exprType() == Expr::VTableCall) { DASSERT_OBJ(selfArg != NULL, in); const Type * classType = fnType->selfParam()->type().dealias().unqualified(); if (classType->typeClass() == Type::Class) { fnVal = genVTableLookup(fn, static_cast<const CompositeType *>(classType), selfArg); } else if (classType->typeClass() == Type::Interface) { fnVal = genITableLookup(fn, static_cast<const CompositeType *>(classType), selfArg); } else { DASSERT(classType->typeClass() == Type::Struct); // Struct or protocol. fnVal = genFunctionValue(fn); } } else { fnVal = genCallableDefn(fn); } Value * result = genCallInstr(fnVal, args, fn->name()); if (in->exprType() == Expr::CtorCall) { // Constructor call returns the 'self' argument. TypeShape selfTypeShape = in->selfArg()->type()->typeShape(); // A large value type will, at this point, be a pointer. if (selfTypeShape == Shape_Small_LValue) { selfArg = builder_.CreateLoad(selfArg, "self"); } result = selfArg; } else if (fnType->isStructReturn()) { result = retVal; } // Clear out all the temporary roots popRootStack(savedRootCount); return result; }
bool CodeGenerator::genFunction(FunctionDefn * fdef) { // Don't generate undefined functions. if (fdef->isUndefined() || fdef->isAbstract() || fdef->isInterfaceMethod()) { return true; } DASSERT_OBJ(fdef->isSingular(), fdef); DASSERT_OBJ(fdef->type(), fdef); DASSERT_OBJ(fdef->type()->isSingular(), fdef); // Don't generate intrinsic functions. if (fdef->isIntrinsic()) { return true; } // Don't generate a function if it has been merged to another function if (fdef->mergeTo() != NULL || fdef->isUndefined()) { return true; } // Create the function Function * f = genFunctionValue(fdef); if (fdef->hasBody() && f->getBasicBlockList().empty()) { FunctionType * ftype = fdef->functionType(); if (fdef->isSynthetic()) { f->setLinkage(GlobalValue::LinkOnceODRLinkage); } if (gcEnabled_) { if (SsGC) { f->setGC("shadow-stack"); } else { f->setGC("tart-gc"); } } if (debug_) { dbgContext_ = genDISubprogram(fdef); //dbgContext_ = genLexicalBlock(fdef->location()); dbgInlineContext_ = DIScope(); setDebugLocation(fdef->location()); } BasicBlock * prologue = BasicBlock::Create(context_, "prologue", f); // Create the LLVM Basic Blocks corresponding to each high level BB. // BlockList & blocks = fdef->blocks(); // for (BlockList::iterator b = blocks.begin(); b != blocks.end(); ++b) { // Block * blk = *b; // blk->setIRBlock(BasicBlock::Create(context_, blk->label(), f)); // } builder_.SetInsertPoint(prologue); // Handle the explicit parameters unsigned param_index = 0; Function::arg_iterator it = f->arg_begin(); Value * saveStructRet = structRet_; if (ftype->isStructReturn()) { it->addAttr(llvm::Attribute::StructRet); structRet_ = it; ++it; } // Handle the 'self' parameter if (ftype->selfParam() != NULL) { ParameterDefn * selfParam = ftype->selfParam(); const Type * selfParamType = selfParam->type().unqualified(); DASSERT_OBJ(fdef->storageClass() == Storage_Instance || fdef->storageClass() == Storage_Local, fdef); DASSERT_OBJ(it != f->arg_end(), ftype); // Check if the self param is a root. if (selfParamType->isReferenceType()) { selfParam->setFlag(ParameterDefn::LValueParam, true); Value * selfAlloca = builder_.CreateAlloca( selfParam->type()->irEmbeddedType(), 0, "self.alloca"); builder_.CreateStore(it, selfAlloca); selfParam->setIRValue(selfAlloca); markGCRoot(selfAlloca, NULL, "self.alloca"); } else { // Since selfParam is always a pointer, we don't need to mark the object pointed // to as a root, since the next call frame up is responsible for tracing it. ftype->selfParam()->setIRValue(it); } it->setName("self"); ++it; } // If this function needs to make allocations, cache a copy of the // allocation context pointer for this thread, since it can on some // platforms be expensive to look up. if (fdef->flags() & FunctionDefn::MakesAllocs) { Function * gcGetAllocContext = genFunctionValue(gc_allocContext); gcAllocContext_ = builder_.CreateCall(gcGetAllocContext, "allocCtx"); } for (; it != f->arg_end(); ++it, ++param_index) { // Set the name of the Nth parameter ParameterDefn * param = ftype->params()[param_index]; DASSERT_OBJ(param != NULL, fdef); DASSERT_OBJ(param->storageClass() == Storage_Local, param); QualifiedType paramType = param->internalType(); it->setName(param->name()); Value * paramValue = it; // If the parameter is a shared reference, then create the shared ref. if (param->isSharedRef()) { genLocalVar(param, paramValue); genGCRoot(param->irValue(), param->sharedRefType(), param->name()); continue; } // If the parameter type contains any reference types, then the parameter needs // to be a root. bool paramIsRoot = false; if (paramType->isReferenceType()) { param->setFlag(ParameterDefn::LValueParam, true); paramIsRoot = true; } else if (paramType->containsReferenceType()) { // TODO: Handle roots of various shapes //param->setFlag(ParameterDefn::LValueParam, true); } // See if we need to make a local copy of the param. if (param->isLValue()) { Value * paramAlloca = builder_.CreateAlloca(paramType->irEmbeddedType(), 0, param->name()); param->setIRValue(paramAlloca); if (paramType->typeShape() == Shape_Large_Value) { paramValue = builder_.CreateLoad(paramValue); } builder_.CreateStore(paramValue, paramAlloca); if (paramIsRoot) { genGCRoot(paramAlloca, paramType.unqualified(), param->name()); } } else { param->setIRValue(paramValue); } } // Generate the body Function * saveFn = currentFn_; currentFn_ = f; #if 0 if (fdef->isGenerator()) { assert(false); } else { #endif genLocalStorage(fdef->localScopes()); genDISubprogramStart(fdef); genLocalRoots(fdef->localScopes()); BasicBlock * blkEntry = createBlock("entry"); builder_.SetInsertPoint(blkEntry); genExpr(fdef->body()); if (!atTerminator()) { if (fdef->returnType()->isVoidType()) { builder_.CreateRetVoid(); } else { // TODO: Use the location from the last statement of the function. diag.error(fdef) << "Missing return statement at end of non-void function."; } } gcAllocContext_ = NULL; #if 0 } #endif builder_.SetInsertPoint(prologue); builder_.CreateBr(blkEntry); currentFn_ = saveFn; structRet_ = saveStructRet; if (!diag.inRecovery()) { if (verifyFunction(*f, PrintMessageAction)) { f->dump(); DFAIL("Function failed to verify"); } } //if (debug_ && !dbgContext_.isNull() && !dbgContext_.Verify()) { // dbgContext_.Verify(); // DFAIL("BAD DBG"); //} dbgContext_ = DIScope(); dbgInlineContext_ = DIScope(); builder_.ClearInsertionPoint(); builder_.SetCurrentDebugLocation(llvm::DebugLoc()); } return true; }
bool CallCandidate::unify(CallExpr * callExpr, BindingEnv & env, FormatStream * errStrm) { size_t argCount = callExpr_->argCount(); for (size_t argIndex = 0; argIndex < argCount; ++argIndex) { QualifiedType paramType = this->paramType(argIndex); AnalyzerBase::analyzeType(paramType, Task_PrepConversion); } if (!isTemplate_) { return true; } // Now, for each parameter attempt unification. SourceContext callSite(callExpr, NULL, callExpr); SourceContext candidateSite(method_, &callSite, method_, Format_Type); // Unify explicit template arguments with template parameters. if (spCandidate_ != NULL) { if (!spCandidate_->unify(&candidateSite, env)) { return false; } } //bool hasUnsizedArgs = false; for (size_t argIndex = 0; argIndex < argCount; ++argIndex) { Expr * argExpr = callExpr_->arg(argIndex); QualifiedType argType = argExpr->type(); QualifiedType paramType = this->paramType(argIndex); // Skip unsized type integers for now, we'll bind them on the second pass. if (!env.unify(&candidateSite, paramType, argType, Constraint::LOWER_BOUND)) { if (errStrm) { *errStrm << "Argument #" << argIndex + 1 << " type " << paramType << " failed to unify with " << argType; } return false; } } // Unify the return type QualifiedType expectedReturnType = callExpr_->expectedReturnType(); if (!expectedReturnType.isNull()) { if (!env.unify(&candidateSite, resultType_, expectedReturnType, Constraint::UPPER_BOUND)) { if (errStrm) { *errStrm << "Return type " << expectedReturnType << " failed to unify with " << resultType_; } return false; } } // A proper unification requires that each template parameter be bound to something. for (Defn * def = method_; def != NULL && !def->isSingular(); def = def->parentDefn()) { Template * ts = def->templateSignature(); if (ts != NULL) { size_t numParams = ts->typeParams()->size(); // For each template parameter, create a TypeAssignment instance. for (size_t i = 0; i < numParams; ++i) { const TypeVariable * var = ts->patternVar(i); const TypeAssignment * ta = env.getAssignment(var, this); if (ta->constraints().empty()) { if (errStrm) { *errStrm << "No binding for template parameter " << var << " in " << env; } return false; } } } } return true; }