1. Rewrite reflection of parameter packet in RSExportFunc. In order to
generate the correct call (i.e., all parameters in the call instruction
must match the target function signature) regardless of ABI, we construct type
of parameter packet directly from target function prototype (which may not be
the same as the one declared in the source since Clang may modified it to
the type which is better supported by the target ABI.)
2. Rewrite reflection of RSExportRecordType to use clang::ASTRecordLayout. This
corrects the reflection of struct type when tail padding and field alignment
involve. This improves stability of RSExportRecordType reflection.
diff --git a/slang_rs_export_func.cpp b/slang_rs_export_func.cpp
index 19d6cee..8e0d160 100644
--- a/slang_rs_export_func.cpp
+++ b/slang_rs_export_func.cpp
@@ -1,11 +1,12 @@
#include "slang_rs_export_func.h"
+#include "llvm/DerivedTypes.h"
#include "llvm/Target/TargetData.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "slang_rs_context.h"
-#include "slang_rs_export_type.h"
using namespace slang;
@@ -18,98 +19,111 @@
F = new RSExportFunc(Context, Name);
- // Check whether the parameters passed to the function is exportable
- for (unsigned i = 0, e = FD->getNumParams(); i != e; i++) {
- const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
- const llvm::StringRef ParamName = PVD->getName();
+ // Initialize mParamPacketType
+ if (FD->getNumParams() <= 0) {
+ F->mParamPacketType = NULL;
+ } else {
+ clang::ASTContext *Ctx = Context->getASTContext();
- assert(!ParamName.empty() && "Parameter must have a name");
+ std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_func_param:");
+ Id.append(F->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX);
- if (PVD->hasDefaultArg())
- fprintf(stderr,
- "Note: parameter '%s' in function '%s' has default value "
- "will not support\n",
- ParamName.str().c_str(),
- Name.str().c_str());
+ clang::RecordDecl *RD =
+ clang::RecordDecl::Create(*Ctx, clang::TTK_Struct,
+ Ctx->getTranslationUnitDecl(),
+ clang::SourceLocation(),
+ &Ctx->Idents.get(Id));
- // Check type
- RSExportType *PET = RSExportType::CreateFromDecl(Context, PVD);
- if (PET != NULL) {
- F->mParams.push_back(new Parameter(PET, ParamName));
- } else {
- fprintf(stderr, "Note: parameter '%s' in function '%s' uses unsupported "
- "type\n", ParamName.str().c_str(), Name.str().c_str());
+ for (unsigned i = 0; i < FD->getNumParams(); i++) {
+ const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
+ llvm::StringRef ParamName = PVD->getName();
+
+ if (PVD->hasDefaultArg())
+ fprintf(stderr, "Note: parameter '%s' in function '%s' has default "
+ "value which is not supported\n",
+ ParamName.str().c_str(),
+ F->getName().c_str());
+
+ clang::FieldDecl *FD =
+ clang::FieldDecl::Create(*Ctx,
+ RD,
+ clang::SourceLocation(),
+ PVD->getIdentifier(),
+ PVD->getOriginalType(),
+ NULL,
+ /* BitWidth = */NULL,
+ /* Mutable = */false);
+ RD->addDecl(FD);
+ }
+
+ RD->completeDefinition();
+
+ clang::QualType T = Ctx->getTagDeclType(RD);
+ assert(!T.isNull());
+
+ RSExportType *ET =
+ RSExportType::Create(Context, T.getTypePtr());
+
+ if (ET == NULL) {
+ fprintf(stderr, "Failed to export the function %s. There's at least one "
+ "parameter whose type is not supported by the "
+ "reflection", F->getName().c_str());
delete F;
return NULL;
}
+
+ assert((ET->getClass() == RSExportType::ExportClassRecord) &&
+ "Parameter packet must be a record");
+
+ F->mParamPacketType = static_cast<RSExportRecordType *>(ET);
}
return F;
}
-const RSExportRecordType *RSExportFunc::getParamPacketType() const {
- // Pack parameters
- if ((mParamPacketType == NULL) && hasParam()) {
- int Index = 0;
- RSExportRecordType *ParamPacketType =
- new RSExportRecordType(mContext,
- "",
- /* IsPacked = */false,
- /* IsArtificial = */true);
+bool
+RSExportFunc::checkParameterPacketType(const llvm::StructType *ParamTy) const {
+ if (ParamTy == NULL)
+ return !hasParam();
+ else if (!hasParam())
+ return false;
- for (const_param_iterator PI = params_begin(),
- PE = params_end();
- PI != PE;
- PI++, Index++) {
- // For-Loop's body should be:
- const RSExportFunc::Parameter *P = *PI;
- std::string nam = P->getName();
- const RSExportType *typ = P->getType();
- std::string typNam = typ->getName();
- // If (type conversion is needed)
- if (typNam.find("rs_") == 0) {
- // P's type set to [1 x i32];
- RSExportConstantArrayType *ECT = new RSExportConstantArrayType
- (mContext, "addObj",
- RSExportPrimitiveType::DataTypeSigned32,
- RSExportPrimitiveType::DataKindUser,
- false,
- 1);
- ParamPacketType->mFields.push_back(
- new RSExportRecordType::Field(ECT,
- nam,
- ParamPacketType,
- Index) );
- } else {
- ParamPacketType->mFields.push_back(
- new RSExportRecordType::Field(P->getType(),
- nam,
- ParamPacketType,
- Index) );
- }
- }
+ assert(mParamPacketType != NULL);
+ const RSExportRecordType *ERT = mParamPacketType;
+ // must have same number of elements
+ if (ERT->getFields().size() != ParamTy->getNumElements())
+ return false;
+ const llvm::StructLayout *ParamTySL =
+ mContext->getTargetData()->getStructLayout(ParamTy);
- ParamPacketType->AllocSize =
- mContext->getTargetData()->getTypeAllocSize(
- ParamPacketType->getLLVMType());
+ unsigned Index = 0;
+ for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
+ FE = ERT->fields_end(); FI != FE; FI++, Index++) {
+ const RSExportRecordType::Field *F = *FI;
- mParamPacketType = ParamPacketType;
+ const llvm::Type *T1 = F->getType()->getLLVMType();
+ const llvm::Type *T2 = ParamTy->getTypeAtIndex(Index);
+
+ // Fast check
+ if (T1 == T2)
+ continue;
+
+ // Check offset
+ size_t T1Offset = F->getOffsetInParent();
+ size_t T2Offset = ParamTySL->getElementOffset(Index);
+
+ if (T1Offset != T2Offset)
+ return false;
+
+ // Check size
+ size_t T1Size = RSExportType::GetTypeAllocSize(F->getType());
+ size_t T2Size = mContext->getTargetData()->getTypeAllocSize(T2);
+
+ if (T1Size != T2Size)
+ return false;
}
- return mParamPacketType;
-}
-
-RSExportFunc::~RSExportFunc() {
- for (const_param_iterator PI = params_begin(),
- PE = params_end();
- PI != params_end();
- PI++)
- delete *PI;
-
- if (mParamPacketType != NULL)
- delete mParamPacketType;
-
- return;
+ return true;
}