Merge "Fix a bug with compat lib support. Add new namespace to sp<>."
diff --git a/slang_rs_backend.cpp b/slang_rs_backend.cpp
index 3fb9f1a..541efb5 100644
--- a/slang_rs_backend.cpp
+++ b/slang_rs_backend.cpp
@@ -187,321 +187,324 @@
}
///////////////////////////////////////////////////////////////////////////////
+void RSBackend::dumpExportVarInfo(llvm::Module *M) {
+ int slotCount = 0;
+ if (mExportVarMetadata == NULL)
+ mExportVarMetadata = M->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN);
+
+ llvm::SmallVector<llvm::Value*, 2> ExportVarInfo;
+
+ // We emit slot information (#rs_object_slots) for any reference counted
+ // RS type or pointer (which can also be bound).
+
+ for (RSContext::const_export_var_iterator I = mContext->export_vars_begin(),
+ E = mContext->export_vars_end();
+ I != E;
+ I++) {
+ const RSExportVar *EV = *I;
+ const RSExportType *ET = EV->getType();
+ bool countsAsRSObject = false;
+
+ // Variable name
+ ExportVarInfo.push_back(
+ llvm::MDString::get(mLLVMContext, EV->getName().c_str()));
+
+ // Type name
+ switch (ET->getClass()) {
+ case RSExportType::ExportClassPrimitive: {
+ const RSExportPrimitiveType *PT =
+ static_cast<const RSExportPrimitiveType*>(ET);
+ ExportVarInfo.push_back(
+ llvm::MDString::get(
+ mLLVMContext, llvm::utostr_32(PT->getType())));
+ if (PT->isRSObjectType()) {
+ countsAsRSObject = true;
+ }
+ break;
+ }
+ case RSExportType::ExportClassPointer: {
+ ExportVarInfo.push_back(
+ llvm::MDString::get(
+ mLLVMContext, ("*" + static_cast<const RSExportPointerType*>(ET)
+ ->getPointeeType()->getName()).c_str()));
+ break;
+ }
+ case RSExportType::ExportClassMatrix: {
+ ExportVarInfo.push_back(
+ llvm::MDString::get(
+ mLLVMContext, llvm::utostr_32(
+ RSExportPrimitiveType::DataTypeRSMatrix2x2 +
+ static_cast<const RSExportMatrixType*>(ET)->getDim() - 2)));
+ break;
+ }
+ case RSExportType::ExportClassVector:
+ case RSExportType::ExportClassConstantArray:
+ case RSExportType::ExportClassRecord: {
+ ExportVarInfo.push_back(
+ llvm::MDString::get(mLLVMContext,
+ EV->getType()->getName().c_str()));
+ break;
+ }
+ }
+
+ mExportVarMetadata->addOperand(
+ llvm::MDNode::get(mLLVMContext, ExportVarInfo));
+ ExportVarInfo.clear();
+
+ if (mRSObjectSlotsMetadata == NULL) {
+ mRSObjectSlotsMetadata =
+ M->getOrInsertNamedMetadata(RS_OBJECT_SLOTS_MN);
+ }
+
+ if (countsAsRSObject) {
+ mRSObjectSlotsMetadata->addOperand(llvm::MDNode::get(mLLVMContext,
+ llvm::MDString::get(mLLVMContext, llvm::utostr_32(slotCount))));
+ }
+
+ slotCount++;
+ }
+}
+
+void RSBackend::dumpExportFunctionInfo(llvm::Module *M) {
+ if (mExportFuncMetadata == NULL)
+ mExportFuncMetadata =
+ M->getOrInsertNamedMetadata(RS_EXPORT_FUNC_MN);
+
+ llvm::SmallVector<llvm::Value*, 1> ExportFuncInfo;
+
+ for (RSContext::const_export_func_iterator
+ I = mContext->export_funcs_begin(),
+ E = mContext->export_funcs_end();
+ I != E;
+ I++) {
+ const RSExportFunc *EF = *I;
+
+ // Function name
+ if (!EF->hasParam()) {
+ ExportFuncInfo.push_back(llvm::MDString::get(mLLVMContext,
+ EF->getName().c_str()));
+ } else {
+ llvm::Function *F = M->getFunction(EF->getName());
+ llvm::Function *HelperFunction;
+ const std::string HelperFunctionName(".helper_" + EF->getName());
+
+ slangAssert(F && "Function marked as exported disappeared in Bitcode");
+
+ // Create helper function
+ {
+ llvm::StructType *HelperFunctionParameterTy = NULL;
+
+ if (!F->getArgumentList().empty()) {
+ std::vector<llvm::Type*> HelperFunctionParameterTys;
+ for (llvm::Function::arg_iterator AI = F->arg_begin(),
+ AE = F->arg_end(); AI != AE; AI++)
+ HelperFunctionParameterTys.push_back(AI->getType());
+
+ HelperFunctionParameterTy =
+ llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys);
+ }
+
+ if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) {
+ fprintf(stderr, "Failed to export function %s: parameter type "
+ "mismatch during creation of helper function.\n",
+ EF->getName().c_str());
+
+ const RSExportRecordType *Expected = EF->getParamPacketType();
+ if (Expected) {
+ fprintf(stderr, "Expected:\n");
+ Expected->getLLVMType()->dump();
+ }
+ if (HelperFunctionParameterTy) {
+ fprintf(stderr, "Got:\n");
+ HelperFunctionParameterTy->dump();
+ }
+ }
+
+ std::vector<llvm::Type*> Params;
+ if (HelperFunctionParameterTy) {
+ llvm::PointerType *HelperFunctionParameterTyP =
+ llvm::PointerType::getUnqual(HelperFunctionParameterTy);
+ Params.push_back(HelperFunctionParameterTyP);
+ }
+
+ llvm::FunctionType * HelperFunctionType =
+ llvm::FunctionType::get(F->getReturnType(),
+ Params,
+ /* IsVarArgs = */false);
+
+ HelperFunction =
+ llvm::Function::Create(HelperFunctionType,
+ llvm::GlobalValue::ExternalLinkage,
+ HelperFunctionName,
+ M);
+
+ HelperFunction->addFnAttr(llvm::Attribute::NoInline);
+ HelperFunction->setCallingConv(F->getCallingConv());
+
+ // Create helper function body
+ {
+ llvm::Argument *HelperFunctionParameter =
+ &(*HelperFunction->arg_begin());
+ llvm::BasicBlock *BB =
+ llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction);
+ llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB);
+ llvm::SmallVector<llvm::Value*, 6> Params;
+ llvm::Value *Idx[2];
+
+ Idx[0] =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0);
+
+ // getelementptr and load instruction for all elements in
+ // parameter .p
+ for (size_t i = 0; i < EF->getNumParameters(); i++) {
+ // getelementptr
+ Idx[1] = llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(mLLVMContext), i);
+
+ llvm::Value *Ptr =
+ IB->CreateInBoundsGEP(HelperFunctionParameter, Idx);
+
+ // load
+ llvm::Value *V = IB->CreateLoad(Ptr);
+ Params.push_back(V);
+ }
+
+ // Call and pass the all elements as parameter to F
+ llvm::CallInst *CI = IB->CreateCall(F, Params);
+
+ CI->setCallingConv(F->getCallingConv());
+
+ if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext))
+ IB->CreateRetVoid();
+ else
+ IB->CreateRet(CI);
+
+ delete IB;
+ }
+ }
+
+ ExportFuncInfo.push_back(
+ llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str()));
+ }
+
+ mExportFuncMetadata->addOperand(
+ llvm::MDNode::get(mLLVMContext, ExportFuncInfo));
+ ExportFuncInfo.clear();
+ }
+}
+
+void RSBackend::dumpExportForEachInfo(llvm::Module *M) {
+ if (mExportForEachNameMetadata == NULL) {
+ mExportForEachNameMetadata =
+ M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_NAME_MN);
+ }
+ if (mExportForEachSignatureMetadata == NULL) {
+ mExportForEachSignatureMetadata =
+ M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_MN);
+ }
+
+ llvm::SmallVector<llvm::Value*, 1> ExportForEachName;
+ llvm::SmallVector<llvm::Value*, 1> ExportForEachInfo;
+
+ for (RSContext::const_export_foreach_iterator
+ I = mContext->export_foreach_begin(),
+ E = mContext->export_foreach_end();
+ I != E;
+ I++) {
+ const RSExportForEach *EFE = *I;
+
+ ExportForEachName.push_back(
+ llvm::MDString::get(mLLVMContext, EFE->getName().c_str()));
+
+ mExportForEachNameMetadata->addOperand(
+ llvm::MDNode::get(mLLVMContext, ExportForEachName));
+ ExportForEachName.clear();
+
+ ExportForEachInfo.push_back(
+ llvm::MDString::get(mLLVMContext,
+ llvm::utostr_32(EFE->getSignatureMetadata())));
+
+ mExportForEachSignatureMetadata->addOperand(
+ llvm::MDNode::get(mLLVMContext, ExportForEachInfo));
+ ExportForEachInfo.clear();
+ }
+}
+
+void RSBackend::dumpExportTypeInfo(llvm::Module *M) {
+ llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo;
+
+ for (RSContext::const_export_type_iterator
+ I = mContext->export_types_begin(),
+ E = mContext->export_types_end();
+ I != E;
+ I++) {
+ // First, dump type name list to export
+ const RSExportType *ET = I->getValue();
+
+ ExportTypeInfo.clear();
+ // Type name
+ ExportTypeInfo.push_back(
+ llvm::MDString::get(mLLVMContext, ET->getName().c_str()));
+
+ if (ET->getClass() == RSExportType::ExportClassRecord) {
+ const RSExportRecordType *ERT =
+ static_cast<const RSExportRecordType*>(ET);
+
+ if (mExportTypeMetadata == NULL)
+ mExportTypeMetadata =
+ M->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN);
+
+ mExportTypeMetadata->addOperand(
+ llvm::MDNode::get(mLLVMContext, ExportTypeInfo));
+
+ // Now, export struct field information to %[struct name]
+ std::string StructInfoMetadataName("%");
+ StructInfoMetadataName.append(ET->getName());
+ llvm::NamedMDNode *StructInfoMetadata =
+ M->getOrInsertNamedMetadata(StructInfoMetadataName);
+ llvm::SmallVector<llvm::Value*, 3> FieldInfo;
+
+ slangAssert(StructInfoMetadata->getNumOperands() == 0 &&
+ "Metadata with same name was created before");
+ for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
+ FE = ERT->fields_end();
+ FI != FE;
+ FI++) {
+ const RSExportRecordType::Field *F = *FI;
+
+ // 1. field name
+ FieldInfo.push_back(llvm::MDString::get(mLLVMContext,
+ F->getName().c_str()));
+
+ // 2. field type name
+ FieldInfo.push_back(
+ llvm::MDString::get(mLLVMContext,
+ F->getType()->getName().c_str()));
+
+ StructInfoMetadata->addOperand(
+ llvm::MDNode::get(mLLVMContext, FieldInfo));
+ FieldInfo.clear();
+ }
+ } // ET->getClass() == RSExportType::ExportClassRecord
+ }
+}
+
void RSBackend::HandleTranslationUnitPost(llvm::Module *M) {
if (!mContext->processExport()) {
return;
}
- // Write optimization level
- llvm::SmallVector<llvm::Value*, 1> OptimizationOption;
- OptimizationOption.push_back(llvm::ConstantInt::get(
- mLLVMContext, llvm::APInt(32, mCodeGenOpts.OptimizationLevel)));
+ if (mContext->hasExportVar())
+ dumpExportVarInfo(M);
- // Dump export variable info
- if (mContext->hasExportVar()) {
- int slotCount = 0;
- if (mExportVarMetadata == NULL)
- mExportVarMetadata = M->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN);
+ if (mContext->hasExportFunc())
+ dumpExportFunctionInfo(M);
- llvm::SmallVector<llvm::Value*, 2> ExportVarInfo;
+ if (mContext->hasExportForEach())
+ dumpExportForEachInfo(M);
- // We emit slot information (#rs_object_slots) for any reference counted
- // RS type or pointer (which can also be bound).
-
- for (RSContext::const_export_var_iterator I = mContext->export_vars_begin(),
- E = mContext->export_vars_end();
- I != E;
- I++) {
- const RSExportVar *EV = *I;
- const RSExportType *ET = EV->getType();
- bool countsAsRSObject = false;
-
- // Variable name
- ExportVarInfo.push_back(
- llvm::MDString::get(mLLVMContext, EV->getName().c_str()));
-
- // Type name
- switch (ET->getClass()) {
- case RSExportType::ExportClassPrimitive: {
- const RSExportPrimitiveType *PT =
- static_cast<const RSExportPrimitiveType*>(ET);
- ExportVarInfo.push_back(
- llvm::MDString::get(
- mLLVMContext, llvm::utostr_32(PT->getType())));
- if (PT->isRSObjectType()) {
- countsAsRSObject = true;
- }
- break;
- }
- case RSExportType::ExportClassPointer: {
- ExportVarInfo.push_back(
- llvm::MDString::get(
- mLLVMContext, ("*" + static_cast<const RSExportPointerType*>(ET)
- ->getPointeeType()->getName()).c_str()));
- break;
- }
- case RSExportType::ExportClassMatrix: {
- ExportVarInfo.push_back(
- llvm::MDString::get(
- mLLVMContext, llvm::utostr_32(
- RSExportPrimitiveType::DataTypeRSMatrix2x2 +
- static_cast<const RSExportMatrixType*>(ET)->getDim() - 2)));
- break;
- }
- case RSExportType::ExportClassVector:
- case RSExportType::ExportClassConstantArray:
- case RSExportType::ExportClassRecord: {
- ExportVarInfo.push_back(
- llvm::MDString::get(mLLVMContext,
- EV->getType()->getName().c_str()));
- break;
- }
- }
-
- mExportVarMetadata->addOperand(
- llvm::MDNode::get(mLLVMContext, ExportVarInfo));
- ExportVarInfo.clear();
-
- if (mRSObjectSlotsMetadata == NULL) {
- mRSObjectSlotsMetadata =
- M->getOrInsertNamedMetadata(RS_OBJECT_SLOTS_MN);
- }
-
- if (countsAsRSObject) {
- mRSObjectSlotsMetadata->addOperand(llvm::MDNode::get(mLLVMContext,
- llvm::MDString::get(mLLVMContext, llvm::utostr_32(slotCount))));
- }
-
- slotCount++;
- }
- }
-
- // Dump export function info
- if (mContext->hasExportFunc()) {
- if (mExportFuncMetadata == NULL)
- mExportFuncMetadata =
- M->getOrInsertNamedMetadata(RS_EXPORT_FUNC_MN);
-
- llvm::SmallVector<llvm::Value*, 1> ExportFuncInfo;
-
- for (RSContext::const_export_func_iterator
- I = mContext->export_funcs_begin(),
- E = mContext->export_funcs_end();
- I != E;
- I++) {
- const RSExportFunc *EF = *I;
-
- // Function name
- if (!EF->hasParam()) {
- ExportFuncInfo.push_back(llvm::MDString::get(mLLVMContext,
- EF->getName().c_str()));
- } else {
- llvm::Function *F = M->getFunction(EF->getName());
- llvm::Function *HelperFunction;
- const std::string HelperFunctionName(".helper_" + EF->getName());
-
- slangAssert(F && "Function marked as exported disappeared in Bitcode");
-
- // Create helper function
- {
- llvm::StructType *HelperFunctionParameterTy = NULL;
-
- if (!F->getArgumentList().empty()) {
- std::vector<llvm::Type*> HelperFunctionParameterTys;
- for (llvm::Function::arg_iterator AI = F->arg_begin(),
- AE = F->arg_end(); AI != AE; AI++)
- HelperFunctionParameterTys.push_back(AI->getType());
-
- HelperFunctionParameterTy =
- llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys);
- }
-
- if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) {
- fprintf(stderr, "Failed to export function %s: parameter type "
- "mismatch during creation of helper function.\n",
- EF->getName().c_str());
-
- const RSExportRecordType *Expected = EF->getParamPacketType();
- if (Expected) {
- fprintf(stderr, "Expected:\n");
- Expected->getLLVMType()->dump();
- }
- if (HelperFunctionParameterTy) {
- fprintf(stderr, "Got:\n");
- HelperFunctionParameterTy->dump();
- }
- }
-
- std::vector<llvm::Type*> Params;
- if (HelperFunctionParameterTy) {
- llvm::PointerType *HelperFunctionParameterTyP =
- llvm::PointerType::getUnqual(HelperFunctionParameterTy);
- Params.push_back(HelperFunctionParameterTyP);
- }
-
- llvm::FunctionType * HelperFunctionType =
- llvm::FunctionType::get(F->getReturnType(),
- Params,
- /* IsVarArgs = */false);
-
- HelperFunction =
- llvm::Function::Create(HelperFunctionType,
- llvm::GlobalValue::ExternalLinkage,
- HelperFunctionName,
- M);
-
- HelperFunction->addFnAttr(llvm::Attribute::NoInline);
- HelperFunction->setCallingConv(F->getCallingConv());
-
- // Create helper function body
- {
- llvm::Argument *HelperFunctionParameter =
- &(*HelperFunction->arg_begin());
- llvm::BasicBlock *BB =
- llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction);
- llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB);
- llvm::SmallVector<llvm::Value*, 6> Params;
- llvm::Value *Idx[2];
-
- Idx[0] =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0);
-
- // getelementptr and load instruction for all elements in
- // parameter .p
- for (size_t i = 0; i < EF->getNumParameters(); i++) {
- // getelementptr
- Idx[1] = llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(mLLVMContext), i);
-
- llvm::Value *Ptr =
- IB->CreateInBoundsGEP(HelperFunctionParameter, Idx);
-
- // load
- llvm::Value *V = IB->CreateLoad(Ptr);
- Params.push_back(V);
- }
-
- // Call and pass the all elements as parameter to F
- llvm::CallInst *CI = IB->CreateCall(F, Params);
-
- CI->setCallingConv(F->getCallingConv());
-
- if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext))
- IB->CreateRetVoid();
- else
- IB->CreateRet(CI);
-
- delete IB;
- }
- }
-
- ExportFuncInfo.push_back(
- llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str()));
- }
-
- mExportFuncMetadata->addOperand(
- llvm::MDNode::get(mLLVMContext, ExportFuncInfo));
- ExportFuncInfo.clear();
- }
- }
-
- // Dump export function info
- if (mContext->hasExportForEach()) {
- if (mExportForEachNameMetadata == NULL) {
- mExportForEachNameMetadata =
- M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_NAME_MN);
- }
- if (mExportForEachSignatureMetadata == NULL) {
- mExportForEachSignatureMetadata =
- M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_MN);
- }
-
- llvm::SmallVector<llvm::Value*, 1> ExportForEachName;
- llvm::SmallVector<llvm::Value*, 1> ExportForEachInfo;
-
- for (RSContext::const_export_foreach_iterator
- I = mContext->export_foreach_begin(),
- E = mContext->export_foreach_end();
- I != E;
- I++) {
- const RSExportForEach *EFE = *I;
-
- ExportForEachName.push_back(
- llvm::MDString::get(mLLVMContext, EFE->getName().c_str()));
-
- mExportForEachNameMetadata->addOperand(
- llvm::MDNode::get(mLLVMContext, ExportForEachName));
- ExportForEachName.clear();
-
- ExportForEachInfo.push_back(
- llvm::MDString::get(mLLVMContext,
- llvm::utostr_32(EFE->getSignatureMetadata())));
-
- mExportForEachSignatureMetadata->addOperand(
- llvm::MDNode::get(mLLVMContext, ExportForEachInfo));
- ExportForEachInfo.clear();
- }
- }
-
- // Dump export type info
- if (mContext->hasExportType()) {
- llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo;
-
- for (RSContext::const_export_type_iterator
- I = mContext->export_types_begin(),
- E = mContext->export_types_end();
- I != E;
- I++) {
- // First, dump type name list to export
- const RSExportType *ET = I->getValue();
-
- ExportTypeInfo.clear();
- // Type name
- ExportTypeInfo.push_back(
- llvm::MDString::get(mLLVMContext, ET->getName().c_str()));
-
- if (ET->getClass() == RSExportType::ExportClassRecord) {
- const RSExportRecordType *ERT =
- static_cast<const RSExportRecordType*>(ET);
-
- if (mExportTypeMetadata == NULL)
- mExportTypeMetadata =
- M->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN);
-
- mExportTypeMetadata->addOperand(
- llvm::MDNode::get(mLLVMContext, ExportTypeInfo));
-
- // Now, export struct field information to %[struct name]
- std::string StructInfoMetadataName("%");
- StructInfoMetadataName.append(ET->getName());
- llvm::NamedMDNode *StructInfoMetadata =
- M->getOrInsertNamedMetadata(StructInfoMetadataName);
- llvm::SmallVector<llvm::Value*, 3> FieldInfo;
-
- slangAssert(StructInfoMetadata->getNumOperands() == 0 &&
- "Metadata with same name was created before");
- for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
- FE = ERT->fields_end();
- FI != FE;
- FI++) {
- const RSExportRecordType::Field *F = *FI;
-
- // 1. field name
- FieldInfo.push_back(llvm::MDString::get(mLLVMContext,
- F->getName().c_str()));
-
- // 2. field type name
- FieldInfo.push_back(
- llvm::MDString::get(mLLVMContext,
- F->getType()->getName().c_str()));
-
- StructInfoMetadata->addOperand(
- llvm::MDNode::get(mLLVMContext, FieldInfo));
- FieldInfo.clear();
- }
- } // ET->getClass() == RSExportType::ExportClassRecord
- }
- }
+ if (mContext->hasExportType())
+ dumpExportTypeInfo(M);
return;
}
diff --git a/slang_rs_backend.h b/slang_rs_backend.h
index 80c643d..2d6ab72 100644
--- a/slang_rs_backend.h
+++ b/slang_rs_backend.h
@@ -64,6 +64,11 @@
void AnnotateFunction(clang::FunctionDecl *FD);
+ void dumpExportVarInfo(llvm::Module *M);
+ void dumpExportFunctionInfo(llvm::Module *M);
+ void dumpExportForEachInfo(llvm::Module *M);
+ void dumpExportTypeInfo(llvm::Module *M);
+
protected:
virtual unsigned int getTargetAPI() const {
return mContext->getTargetAPI();
diff --git a/slang_rs_check_ast.cpp b/slang_rs_check_ast.cpp
index 845db4c..14ee822 100644
--- a/slang_rs_check_ast.cpp
+++ b/slang_rs_check_ast.cpp
@@ -36,6 +36,117 @@
}
}
+void RSCheckAST::WarnOnSetElementAt(clang::CallExpr *E) {
+ clang::FunctionDecl *Decl;
+ clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
+ Decl = clang::dyn_cast_or_null<clang::FunctionDecl>(E->getCalleeDecl());
+
+ if (!Decl || Decl->getNameAsString() != std::string("rsSetElementAt")) {
+ return;
+ }
+
+ clang::Expr *Expr;
+ clang::ImplicitCastExpr *ImplCast;
+ Expr = E->getArg(1);
+ ImplCast = clang::dyn_cast_or_null<clang::ImplicitCastExpr>(Expr);
+
+ if (!ImplCast) {
+ return;
+ }
+
+ const clang::Type *Ty;
+ const clang::VectorType *VectorTy;
+ const clang::BuiltinType *ElementTy;
+ Ty = ImplCast->getSubExpr()->getType()->getPointeeType()
+ ->getUnqualifiedDesugaredType();
+ VectorTy = clang::dyn_cast_or_null<clang::VectorType>(Ty);
+
+ if (VectorTy) {
+ ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>(
+ VectorTy->getElementType()->getUnqualifiedDesugaredType());
+ } else {
+ ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>(
+ Ty->getUnqualifiedDesugaredType());
+ }
+
+ if (!ElementTy) {
+ return;
+ }
+
+ // We only support vectors with 2, 3 or 4 elements.
+ if (VectorTy) {
+ switch (VectorTy->getNumElements()) {
+ default:
+ return;
+ case 2:
+ case 3:
+ case 4:
+ break;
+ }
+ }
+
+ const char *Name;
+
+ switch (ElementTy->getKind()) {
+ case clang::BuiltinType::Float:
+ Name = "float";
+ break;
+ case clang::BuiltinType::Double:
+ Name = "double";
+ break;
+ case clang::BuiltinType::Char_S:
+ Name = "char";
+ break;
+ case clang::BuiltinType::Short:
+ Name = "short";
+ break;
+ case clang::BuiltinType::Int:
+ Name = "int";
+ break;
+ case clang::BuiltinType::Long:
+ Name = "long";
+ break;
+ case clang::BuiltinType::UChar:
+ Name = "uchar";
+ break;
+ case clang::BuiltinType::UShort:
+ Name = "ushort";
+ break;
+ case clang::BuiltinType::UInt:
+ Name = "uint";
+ break;
+ case clang::BuiltinType::ULong:
+ Name = "ulong";
+ break;
+ default:
+ return;
+ }
+
+ clang::DiagnosticBuilder DiagBuilder = DiagEngine.Report(
+ clang::FullSourceLoc(E->getLocStart(), mSM),
+ mDiagEngine.getCustomDiagID( clang::DiagnosticsEngine::Warning,
+ "untyped rsSetElementAt() can reduce performance. "
+ "Use rsSetElementAt_%0%1() instead."));
+ DiagBuilder << Name;
+
+ if (VectorTy) {
+ DiagBuilder << VectorTy->getNumElements();
+ } else {
+ DiagBuilder << "";
+ }
+
+ return;
+}
+
+void RSCheckAST::VisitCallExpr(clang::CallExpr *E) {
+ WarnOnSetElementAt(E);
+
+ for (clang::CallExpr::arg_iterator AI = E->arg_begin(), AE = E->arg_end();
+ AI != AE; ++AI) {
+ Visit(*AI);
+ }
+}
+
void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) {
if (!FD) {
return;
diff --git a/slang_rs_check_ast.h b/slang_rs_check_ast.h
index 1700cb7..53be3cf 100644
--- a/slang_rs_check_ast.h
+++ b/slang_rs_check_ast.h
@@ -36,6 +36,14 @@
bool mIsFilterscript;
bool mInKernel;
+ /// @brief Emit warnings for inapproriate uses of rsSetElementAt
+ ///
+ /// We warn in case generic rsSetElementAt() is used even though the user
+ /// could have used a typed rsSetElementAt_<type>() call. Typed calls
+ /// allow more aggressive optimization (e.g. due to better alias analysis
+ /// results). Hence, we want to steer the users to use them.
+ void WarnOnSetElementAt(clang::CallExpr*);
+
public:
explicit RSCheckAST(clang::ASTContext &Con, unsigned int TargetAPI,
bool IsFilterscript)
@@ -47,6 +55,8 @@
void VisitStmt(clang::Stmt *S);
+ void VisitCallExpr(clang::CallExpr *CE);
+
void VisitCastExpr(clang::CastExpr *CE);
void VisitExpr(clang::Expr *E);
diff --git a/tests/F_vector_cast/stderr.txt.expect b/tests/F_vector_cast/stderr.txt.expect
index 84dfc4d..b8fa5ea 100644
--- a/tests/F_vector_cast/stderr.txt.expect
+++ b/tests/F_vector_cast/stderr.txt.expect
@@ -3,3 +3,4 @@
vector_cast.rs:7:9: error: invalid vector cast
vector_cast.rs:14:9: error: invalid vector cast
vector_cast.rs:21:9: error: invalid vector cast
+vector_cast.rs:31:13: error: invalid vector cast
diff --git a/tests/F_vector_cast/vector_cast.rs b/tests/F_vector_cast/vector_cast.rs
index b504103..bd49391 100644
--- a/tests/F_vector_cast/vector_cast.rs
+++ b/tests/F_vector_cast/vector_cast.rs
@@ -21,3 +21,13 @@
u = (uchar4) c;
}
+uchar4 bar(uchar4 u) {
+ return u;
+}
+
+void c2uc_bar() {
+ char4 c;
+ uchar4 u;
+ u = bar((uchar4) c);
+}
+
diff --git a/tests/P_warnings_rsSetElementAt/setelementat.rs b/tests/P_warnings_rsSetElementAt/setelementat.rs
new file mode 100644
index 0000000..032a456
--- /dev/null
+++ b/tests/P_warnings_rsSetElementAt/setelementat.rs
@@ -0,0 +1,52 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+rs_allocation A;
+static void foo() {
+ // Basic scalar and floating point types.
+ float a = 4.0f;
+ double d = 4.0f;
+ float2 a2 = {4.0f, 4.0f};
+ float3 a3 = {4.0f, 4.0f, 4.0f};
+ float4 a4 = {4.0f, 4.0f, 4.0f, 4.0f};
+ char c = 4;
+ uchar uc = 4;
+ short s = 4;
+ ushort us = 4;
+ int i = 4;
+ uint ui = 4;
+ long l = 4;
+ ulong ul = 4;
+
+ rsSetElementAt(A, &a, 0, 0);
+ rsSetElementAt(A, &d, 0, 0);
+ rsSetElementAt(A, &a2, 0, 0);
+ rsSetElementAt(A, &a3, 0, 0);
+ rsSetElementAt(A, &a4, 0, 0);
+ rsSetElementAt(A, &c, 0, 0);
+ rsSetElementAt(A, &uc, 0, 0);
+ rsSetElementAt(A, &s, 0, 0);
+ rsSetElementAt(A, &us, 0, 0);
+ rsSetElementAt(A, &i, 0, 0);
+ rsSetElementAt(A, &ui, 0, 0);
+ rsSetElementAt(A, &l, 0, 0);
+ rsSetElementAt(A, &ul, 0, 0);
+
+ // No warnings for complex data types
+ struct {
+ int A;
+ int B;
+ } P;
+ rsSetElementAt(A, &P, 0, 0);
+
+ // No warning for 'long long'
+ long long LL = 4.0f;
+ rsSetElementAt(A, &LL, 0, 0);
+
+ // Unsupported vector width
+ typedef int int5 __attribute__((ext_vector_type(5)));
+ int5 i5 = {5, 5, 5, 5, 5};
+
+ rsSetElementAt(A, &i5, 0, 0);
+}
+
diff --git a/tests/P_warnings_rsSetElementAt/stderr.txt.expect b/tests/P_warnings_rsSetElementAt/stderr.txt.expect
new file mode 100644
index 0000000..71b7aab
--- /dev/null
+++ b/tests/P_warnings_rsSetElementAt/stderr.txt.expect
@@ -0,0 +1,12 @@
+setelementat.rs:21:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_float() instead.
+setelementat.rs:22:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_double() instead.
+setelementat.rs:23:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_float2() instead.
+setelementat.rs:24:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_float3() instead.
+setelementat.rs:25:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_float4() instead.
+setelementat.rs:26:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_char() instead.
+setelementat.rs:27:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_uchar() instead.
+setelementat.rs:28:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_short() instead.
+setelementat.rs:29:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_ushort() instead.
+setelementat.rs:30:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_int() instead.
+setelementat.rs:31:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_uint() instead.
+setelementat.rs:32:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_long() instead.
diff --git a/tests/P_warnings_rsSetElementAt/stdout.txt.expect b/tests/P_warnings_rsSetElementAt/stdout.txt.expect
new file mode 100644
index 0000000..b10911b
--- /dev/null
+++ b/tests/P_warnings_rsSetElementAt/stdout.txt.expect
@@ -0,0 +1 @@
+Generating ScriptC_setelementat.java ...