void ValuePrinterInfo::Init(clang::QualType Ty) { assert(!Ty.isNull() && "Type must be valid!"); assert(m_Context && "ASTContext cannot be null!"); assert(sizeof(m_Type) >= sizeof(clang::QualType) && "m_Type too small!"); m_Type = *reinterpret_cast<void**>(&Ty); // 1. Get the flags if (Ty.isLocalConstQualified() || Ty.isConstant(*m_Context)){ m_Flags |= VPI_Const; } if (Ty->isPointerType()) { // treat arrary-to-pointer decay as array: QualType PQT = Ty->getPointeeType(); const Type* PTT = PQT.getTypePtr(); if (!PTT || !PTT->isArrayType()) { m_Flags |= VPI_Ptr; if (const RecordType* RT = dyn_cast<RecordType>(Ty.getTypePtr())) if (RecordDecl* RD = RT->getDecl()) { CXXRecordDecl* CRD = dyn_cast<CXXRecordDecl>(RD); if (CRD && CRD->isPolymorphic()) m_Flags |= VPI_Polymorphic; } } } }
std::string GetTypeAsString(const clang::QualType &type) { std::stringstream stream; std::string name = type.getAsString(); // If it is an anonymous structure, print all the fields recursively if (name.substr(0,11) == "struct (ano") { stream << "struct { "; clang::RecordDecl* struct_decl = type.getTypePtr()->getAsStructureType()->getDecl(); // Print the types of all the fields for (const auto* field : struct_decl->fields()) { std::string type = GetTypeAsString(field->getType().getCanonicalType()); std::string name = field->getName(); stream << type; stream << " " << name << "; "; } stream << "}"; } else if (type.getTypePtr()->isBooleanType()) { return "bool"; } else { stream << type.getAsString(); //just print the type } return stream.str(); }
insieme::core::TypePtr VariableLengthArrayExtension::Visit(const clang::QualType& type, insieme::frontend::conversion::Converter& converter) { // we iterate trough the dimensions of the array from left to right. There is no hint // in the C standard how this should be handled and therefore the normal operator precedence is used. if(const clang::VariableArrayType* arrType = llvm::dyn_cast<clang::VariableArrayType>(type.getTypePtr())) { // check if we already converted this decl if(::containsKey(arrayTypeMap, arrType)) return arrayTypeMap[arrType]; // only consider variable array types // create a decl stmt e.g., decl uint v1 = i; core::IRBuilder builder = converter.getIRBuilder(); auto index = converter.convertExpr(arrType->getSizeExpr()); // cast needed from rhs type to int<inf>?! if(index->getType() != builder.getLangBasic().getUIntInf()) { index = builder.numericCast(index, builder.getLangBasic().getUIntInf()); } auto decl = builder.declarationStmt(builder.getLangBasic().getUIntInf(), index); sizes.push_back(decl); // convert the element type (in nested array case this is again a variable array type) core::TypePtr elementType = converter.convertType(arrType->getElementType()); core::TypePtr arrayType = builder.arrayType(elementType, decl->getVariable()); // add type to map arrayTypeMap[arrType] = arrayType; return arrayType; } return nullptr; }
void RSExportReduce::analyzeResultType(StateOfAnalyzeTranslationUnit &S) { if (!(S.FnAccumulatorOk && S.FnOutConverterOk)) { // No idea what the result type is slangAssert(!S.Ok); return; } struct ResultInfoType { const clang::QualType QType; clang::VarDecl *const Decl; const char *FnKey; const std::string &FnName; std::function<std::string ()> UnlessOutConverter; } ResultInfo = S.FnOutConverter ? ResultInfoType({ S.FnOutConverterParamFirstTy, S.FnOutConverterParamFirst, KeyOutConverter, mNameOutConverter, []() { return std::string(""); }}) : ResultInfoType({ S.FnAccumulatorParamFirstTy, S.FnAccumulatorParamFirst, KeyAccumulator, mNameAccumulator, []() { return std::string(" unless ") + KeyOutConverter + " is provided"; }}); const clang::QualType PointeeQType = ResultInfo.QType->getPointeeType(); if (PointeeQType->isPointerType()) { S.RSC.ReportError(ResultInfo.Decl->getLocation(), "%0 parameter '%1' (type '%2') must not point to a pointer%3") << S.DiagnosticDescription(ResultInfo.FnKey, ResultInfo.FnName) << ResultInfo.Decl->getName() << ResultInfo.QType.getAsString() << ResultInfo.UnlessOutConverter(); } else if (PointeeQType->isIncompleteType()) { S.RSC.ReportError(ResultInfo.Decl->getLocation(), "%0 parameter '%1' (type '%2') must not point to an incomplete type%3") << S.DiagnosticDescription(ResultInfo.FnKey, ResultInfo.FnName) << ResultInfo.Decl->getName() << ResultInfo.QType.getAsString() << ResultInfo.UnlessOutConverter(); } else if (HasRSObjectType(PointeeQType.getTypePtr())) { S.RSC.ReportError(ResultInfo.Decl->getLocation(), "%0 parameter '%1' (type '%2') must not point to data containing an object type%3") << S.DiagnosticDescription(ResultInfo.FnKey, ResultInfo.FnName) << ResultInfo.Decl->getName() << ResultInfo.QType.getAsString() << ResultInfo.UnlessOutConverter(); } else if (RSExportType::ValidateType(&S.RSC, S.ASTC, PointeeQType, ResultInfo.Decl, ResultInfo.Decl->getLocStart(), S.RSC.getTargetAPI(), false /* IsFilterscript */, true /* IsExtern */)) { // TODO: Better diagnostics on validation or creation failure? if ((mResultType = RSExportType::Create(&S.RSC, PointeeQType.getTypePtr(), NotLegacyKernelArgument, ResultInfo.Decl)) != nullptr) { const RSExportType *CheckType = mResultType; const char *ArrayErrorPhrase = ""; if (mResultType->getClass() == RSExportType::ExportClassConstantArray) { CheckType = static_cast<const RSExportConstantArrayType *>(mResultType)->getElementType(); ArrayErrorPhrase = "n array of"; } switch (CheckType->getClass()) { case RSExportType::ExportClassMatrix: // Not supported for now -- what does a matrix result type mean? S.RSC.ReportError(ResultInfo.Decl->getLocation(), "%0 parameter '%1' (type '%2') must not point to a%3 matrix type%4") << S.DiagnosticDescription(ResultInfo.FnKey, ResultInfo.FnName) << ResultInfo.Decl->getName() << ResultInfo.QType.getAsString() << ArrayErrorPhrase << ResultInfo.UnlessOutConverter(); mResultType = nullptr; break; default: // All's well break; } } } if (mResultType) S.RSC.insertExportReduceResultType(mResultType); else S.Ok = false; }
// Process "void mNameAccumulator(compType *accum, in1Type in1, …, inNType inN[, specialarguments])" void RSExportReduce::analyzeAccumulator(StateOfAnalyzeTranslationUnit &S) { slangAssert(S.FnAccumulator); // Must return void checkVoidReturn(S, FN_IDENT_ACCUMULATOR, S.FnAccumulator); // Must have initial parameter of same type as initializer parameter // (if there is an initializer), followed by at least 1 input if (S.FnAccumulator->getNumParams() < 2) { S.RSC.ReportError(S.FnAccumulator->getLocation(), "%0 must take at least 2 parameters") << S.DiagnosticDescription(KeyAccumulator, mNameAccumulator); S.Ok = S.FnAccumulatorOk = false; return; } S.FnAccumulatorParamFirst = S.FnAccumulator->getParamDecl(0); S.FnAccumulatorParamFirstTy = S.FnAccumulatorParamFirst->getType().getCanonicalType(); // First parameter must be of pointer type if (!S.FnAccumulatorParamFirstTy->isPointerType()) { S.RSC.ReportError(S.FnAccumulator->getLocation(), "%0 parameter '%1' must be of pointer type not '%2'") << S.DiagnosticDescription(KeyAccumulator, mNameAccumulator) << S.FnAccumulatorParamFirst->getName() << S.FnAccumulatorParamFirstTy.getAsString(); S.Ok = S.FnAccumulatorOk = false; return; } // If there is an initializer with a pointer-typed parameter (as // opposed to an initializer with a bad parameter list), then // accumulator first parameter must be of same type as initializer // parameter if (S.FnInitializer && !S.FnInitializerParamTy.isNull() && S.FnInitializerParamTy->isPointerType() && !S.FnAccumulator->getASTContext().hasSameUnqualifiedType( S.FnInitializerParamTy->getPointeeType().getCanonicalType(), S.FnAccumulatorParamFirstTy->getPointeeType().getCanonicalType())) { // <accumulator> parameter '<baz>' (type '<tbaz>') and initializer <goo>() parameter '<gaz>' (type '<tgaz>') // must be pointers to the same type S.RSC.ReportError(S.FnAccumulator->getLocation(), "%0 parameter '%1' (type '%2') and %3 %4() parameter '%5' (type '%6')" " must be pointers to the same type") << S.DiagnosticDescription(KeyAccumulator, mNameAccumulator) << S.FnAccumulatorParamFirst->getName() << S.FnAccumulatorParamFirstTy.getAsString() << KeyInitializer << mNameInitializer << S.FnInitializerParam->getName() << S.FnInitializerParamTy.getAsString(); S.Ok = S.FnAccumulatorOk = false; } if (S.FnAccumulatorOk && S.FnAccumulatorParamFirstTy->getPointeeType()->isFunctionType()) { S.RSC.ReportError(S.FnAccumulator->getLocation(), "%0 parameter '%1' (type '%2') must not be pointer to function type") << S.DiagnosticDescription(KeyAccumulator, mNameAccumulator) << S.FnAccumulatorParamFirst->getName() << S.FnAccumulatorParamFirstTy.getAsString(); S.Ok = S.FnAccumulatorOk = false; } if (S.FnAccumulatorOk && S.FnAccumulatorParamFirstTy->getPointeeType()->isIncompleteType()) { S.RSC.ReportError(S.FnAccumulator->getLocation(), "%0 parameter '%1' (type '%2') must not be pointer to incomplete type") << S.DiagnosticDescription(KeyAccumulator, mNameAccumulator) << S.FnAccumulatorParamFirst->getName() << S.FnAccumulatorParamFirstTy.getAsString(); S.Ok = S.FnAccumulatorOk = false; } if (S.FnAccumulatorOk && HasRSObjectType(S.FnAccumulatorParamFirstTy->getPointeeType().getCanonicalType().getTypePtr())) { S.RSC.ReportError(S.FnAccumulator->getLocation(), "%0 parameter '%1' (type '%2') must not be pointer to data containing an object type") << S.DiagnosticDescription(KeyAccumulator, mNameAccumulator) << S.FnAccumulatorParamFirst->getName() << S.FnAccumulatorParamFirstTy.getAsString(); S.Ok = S.FnAccumulatorOk = false; } // Parameter must not point to const-qualified checkPointeeConstQualified(S, FN_IDENT_ACCUMULATOR, mNameAccumulator, S.FnAccumulatorParamFirst, false); // Analyze special parameters S.Ok &= (S.FnAccumulatorOk &= processSpecialKernelParameters( &S.RSC, std::bind(S.DiagnosticDescription, KeyAccumulator, mNameAccumulator), S.FnAccumulator, &S.FnAccumulatorIndexOfFirstSpecialParameter, &mAccumulatorSignatureMetadata)); // Must have at least an accumulator and an input. // If we get here we know there are at least 2 arguments; so the only problem case is // where we have an accumulator followed immediately by a special parameter. if (S.FnAccumulatorIndexOfFirstSpecialParameter < 2) { slangAssert(S.FnAccumulatorIndexOfFirstSpecialParameter < S.FnAccumulator->getNumParams()); S.RSC.ReportError(S.FnAccumulator->getLocation(), "%0 must have at least 1 input ('%1' is a special parameter)") << S.DiagnosticDescription(KeyAccumulator, mNameAccumulator) << S.FnAccumulator->getParamDecl(S.FnAccumulatorIndexOfFirstSpecialParameter)->getName(); S.Ok = S.FnAccumulatorOk = false; return; } if (S.FnAccumulatorOk) { mAccumulatorSignatureMetadata |= bcinfo::MD_SIG_In; mAccumulatorTypeSize = S.ASTC.getTypeSizeInChars(S.FnAccumulatorParamFirstTy->getPointeeType()).getQuantity(); for (size_t ParamIdx = 1; ParamIdx < S.FnAccumulatorIndexOfFirstSpecialParameter; ++ParamIdx) { const clang::ParmVarDecl *const Param = S.FnAccumulator->getParamDecl(ParamIdx); mAccumulatorIns.push_back(Param); const clang::QualType ParamQType = Param->getType().getCanonicalType(); const clang::Type *ParamType = ParamQType.getTypePtr(); RSExportType *ParamEType = nullptr; if (ParamQType->isPointerType()) { S.RSC.ReportError(Param->getLocation(), "%0 parameter '%1' (type '%2') must not be a pointer") << S.DiagnosticDescription(KeyAccumulator, mNameAccumulator) << Param->getName() << ParamQType.getAsString(); S.Ok = false; } else if (HasRSObjectType(ParamType)) { S.RSC.ReportError(Param->getLocation(), "%0 parameter '%1' (type '%2') must not contain an object type") << S.DiagnosticDescription(KeyAccumulator, mNameAccumulator) << Param->getName() << ParamQType.getAsString(); S.Ok = false; } else if (RSExportType::ValidateType(&S.RSC, S.ASTC, ParamQType, Param, Param->getLocStart(), S.RSC.getTargetAPI(), false /* IsFilterscript */, true /* IsExtern */)) { // TODO: Better diagnostics on validation or creation failure? ParamEType = RSExportType::Create(&S.RSC, ParamType, NotLegacyKernelArgument); S.Ok &= (ParamEType != nullptr); } else { S.Ok = false; } mAccumulatorInTypes.push_back(ParamEType); // possibly nullptr } } }