bool GetFields( RecordDecl * rd, Obj * entries) { //check the fields of this struct, if any one of them is not understandable, then this struct becomes 'opaque' //that is, we insert the type, and link it to its llvm type, so it can be used in terra code //but none of its fields are exposed (since we don't understand the layout) bool opaque = false; for(RecordDecl::field_iterator it = rd->field_begin(), end = rd->field_end(); it != end; ++it) { if(it->isBitField() || it->isAnonymousStructOrUnion() || !it->getDeclName()) { opaque = true; continue; } DeclarationName declname = it->getDeclName(); std::string declstr = declname.getAsString(); QualType FT = it->getType(); Obj fobj; if(!GetType(FT,&fobj)) { opaque = true; continue; } lua_newtable(L); fobj.push(); lua_setfield(L,-2,"type"); lua_pushstring(L,declstr.c_str()); lua_setfield(L,-2,"field"); entries->addentry(); } return !opaque; }
bool GetFuncType(const FunctionType * f, Obj * typ) { Obj returns,parameters; resulttable->newlist(&returns); resulttable->newlist(¶meters); bool valid = true; //decisions about whether this function can be exported or not are delayed until we have seen all the potential problems QualType RT = f->getResultType(); if(!RT->isVoidType()) { Obj rt; if(!GetType(RT,&rt)) { valid = false; } else { rt.push(); returns.addentry(); } } const FunctionProtoType * proto = f->getAs<FunctionProtoType>(); //proto is null if the function was declared without an argument list (e.g. void foo() and not void foo(void)) //we don't support old-style C parameter lists, we just treat them as empty if(proto) { for(size_t i = 0; i < proto->getNumArgs(); i++) { QualType PT = proto->getArgType(i); Obj pt; if(!GetType(PT,&pt)) { valid = false; //keep going with attempting to parse type to make sure we see all the reasons why we cannot support this function } else if(valid) { pt.push(); parameters.addentry(); } } } if(valid) { PushTypeFunction("functype"); parameters.push(); returns.push(); lua_pushboolean(L, proto ? proto->isVariadic() : false); lua_call(L, 3, 1); typ->initFromStack(L,ref_table); } return valid; }
bool VisitTypedefDecl(TypedefDecl * TD) { if(TD == TD->getCanonicalDecl() && TD->getDeclContext()->getDeclKind() == Decl::TranslationUnit) { llvm::StringRef name = TD->getName(); QualType QT = Context->getCanonicalType(TD->getUnderlyingType()); Obj typ; if(GetType(QT,&typ)) { typ.push(); general.setfield(name.str().c_str()); } else { SetErrorReport(name.str().c_str()); } } return true; }
bool GetFuncType(const FunctionType * f, Obj * typ) { Obj returntype,parameters; resulttable->newlist(¶meters); bool valid = true; //decisions about whether this function can be exported or not are delayed until we have seen all the potential problems #if LLVM_VERSION <= 34 QualType RT = f->getResultType(); #else QualType RT = f->getReturnType(); #endif if(RT->isVoidType()) { PushTypeField("unit"); returntype.initFromStack(L, ref_table); } else { if(!GetType(RT,&returntype)) valid = false; } const FunctionProtoType * proto = f->getAs<FunctionProtoType>(); //proto is null if the function was declared without an argument list (e.g. void foo() and not void foo(void)) //we don't support old-style C parameter lists, we just treat them as empty if(proto) { #if LLVM_VERSION >= 35 for(size_t i = 0; i < proto->getNumParams(); i++) { QualType PT = proto->getParamType(i); #else for(size_t i = 0; i < proto->getNumArgs(); i++) { QualType PT = proto->getArgType(i); #endif Obj pt; if(!GetType(PT,&pt)) { valid = false; //keep going with attempting to parse type to make sure we see all the reasons why we cannot support this function } else if(valid) { pt.push(); parameters.addentry(); } } } if(valid) { PushTypeField("functype"); parameters.push(); returntype.push(); lua_pushboolean(L, proto ? proto->isVariadic() : false); lua_call(L, 3, 1); typ->initFromStack(L,ref_table); } return valid; } bool TraverseFunctionDecl(FunctionDecl *f) { // Function name DeclarationName DeclName = f->getNameInfo().getName(); std::string FuncName = DeclName.getAsString(); const FunctionType * fntyp = f->getType()->getAs<FunctionType>(); if(!fntyp) return true; if(f->getStorageClass() == clang::SC_Static) { ImportError("cannot import static functions."); SetErrorReport(FuncName.c_str()); return true; } Obj typ; if(!GetFuncType(fntyp,&typ)) { SetErrorReport(FuncName.c_str()); return true; } std::string InternalName = FuncName; AsmLabelAttr * asmlabel = f->getAttr<AsmLabelAttr>(); if(asmlabel) { InternalName = asmlabel->getLabel(); #ifndef __linux__ //In OSX and Windows LLVM mangles assembler labels by adding a '\01' prefix InternalName.insert(InternalName.begin(), '\01'); #endif } CreateFunction(FuncName,InternalName,&typ); KeepFunctionLive(f);//make sure this function is live in codegen by creating a dummy reference to it (void) is to suppress unused warnings return true; }
bool GetType(QualType T, Obj * tt) { T = Context->getCanonicalType(T); const Type *Ty = T.getTypePtr(); switch (Ty->getTypeClass()) { case Type::Record: { const RecordType *RT = dyn_cast<RecordType>(Ty); RecordDecl * rd = RT->getDecl(); return GetRecordTypeFromDecl(rd, tt); } break; //TODO case Type::Builtin: switch (cast<BuiltinType>(Ty)->getKind()) { case BuiltinType::Void: InitType("opaque",tt); return true; case BuiltinType::Bool: InitType("bool",tt); return true; case BuiltinType::Char_S: case BuiltinType::Char_U: case BuiltinType::SChar: case BuiltinType::UChar: case BuiltinType::Short: case BuiltinType::UShort: case BuiltinType::Int: case BuiltinType::UInt: case BuiltinType::Long: case BuiltinType::ULong: case BuiltinType::LongLong: case BuiltinType::ULongLong: case BuiltinType::WChar_S: case BuiltinType::WChar_U: case BuiltinType::Char16: case BuiltinType::Char32: { std::stringstream ss; if (Ty->isUnsignedIntegerType()) ss << "u"; ss << "int"; int sz = Context->getTypeSize(T); ss << sz; InitType(ss.str().c_str(),tt); return true; } case BuiltinType::Half: break; case BuiltinType::Float: InitType("float",tt); return true; case BuiltinType::Double: InitType("double",tt); return true; case BuiltinType::LongDouble: case BuiltinType::NullPtr: case BuiltinType::UInt128: default: break; } case Type::Complex: case Type::LValueReference: case Type::RValueReference: break; case Type::Pointer: { const PointerType *PTy = cast<PointerType>(Ty); QualType ETy = PTy->getPointeeType(); Obj t2; if(!GetType(ETy,&t2)) { return false; } PushTypeField("pointer"); t2.push(); lua_call(L,1,1); tt->initFromStack(L, ref_table); return true; } case Type::VariableArray: case Type::IncompleteArray: break; case Type::ConstantArray: { Obj at; const ConstantArrayType *ATy = cast<ConstantArrayType>(Ty); int sz = ATy->getSize().getZExtValue(); if(GetType(ATy->getElementType(),&at)) { PushTypeField("array"); at.push(); lua_pushinteger(L, sz); lua_call(L,2,1); tt->initFromStack(L,ref_table); return true; } else { return false; } } break; case Type::ExtVector: case Type::Vector: { //printf("making a vector!\n"); const VectorType *VT = cast<VectorType>(T); Obj at; if(GetType(VT->getElementType(),&at)) { int n = VT->getNumElements(); PushTypeField("vector"); at.push(); lua_pushinteger(L,n); lua_call(L,2,1); tt->initFromStack(L, ref_table); return true; } else { return false; } } break; case Type::FunctionNoProto: break; case Type::FunctionProto: { const FunctionProtoType *FT = cast<FunctionProtoType>(Ty); //call functype... getNumArgs(); if(FT && GetFuncType(FT,tt)) return true; else return false; break; } case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: case Type::Enum: InitType("uint32",tt); return true; case Type::BlockPointer: case Type::MemberPointer: case Type::Atomic: default: break; } std::stringstream ss; ss << "type not understood: " << T.getAsString().c_str() << " " << Ty->getTypeClass(); return ImportError(ss.str().c_str()); }
bool GetRecordTypeFromDecl(RecordDecl * rd, Obj * tt) { if(rd->isStruct() || rd->isUnion()) { std::string name = rd->getName(); Obj * thenamespace = &tagged; if(name == "") { TypedefNameDecl * decl = rd->getTypedefNameForAnonDecl(); if(decl) { thenamespace = &general; name = decl->getName(); } } //if name == "" then we have an anonymous struct if(!thenamespace->obj(name.c_str(),tt)) { PushTypeField("getorcreatecstruct"); lua_pushstring(L, name.c_str()); lua_pushboolean(L, thenamespace == &tagged); lua_call(L,2,1); tt->initFromStack(L,ref_table); if(!tt->boolean("llvm_definingfunction")) { std::string definingfunction; size_t argpos; RegisterRecordType(Context->getRecordType(rd), &definingfunction, &argpos); lua_pushstring(L,definingfunction.c_str()); tt->setfield("llvm_definingfunction"); lua_pushinteger(L,argpos); tt->setfield("llvm_argumentposition"); } if(name != "") { //do not remember a name for an anonymous struct tt->push(); thenamespace->setfield(name.c_str()); //register the type } } if(tt->boolean("undefined") && rd->getDefinition() != NULL) { tt->clearfield("undefined"); RecordDecl * defn = rd->getDefinition(); Obj entries; tt->newlist(&entries); if(GetFields(defn, &entries)) { if(!defn->isUnion()) { //structtype.entries = {entry1, entry2, ... } entries.push(); tt->setfield("entries"); } else { //add as a union: //structtype.entries = { {entry1,entry2,...} } Obj allentries; tt->obj("entries",&allentries); entries.push(); allentries.addentry(); } tt->pushfield("complete"); tt->push(); lua_call(L,1,0); } } return true; } else { return ImportError("non-struct record types are not supported"); } }
bool GetRecordTypeFromDecl(RecordDecl * rd, Obj * tt, std::string * fullname) { if(rd->isStruct() || rd->isUnion()) { std::string name = rd->getName(); //TODO: why do some types not have names? Obj * thenamespace = &tagged; if(name == "") { TypedefNameDecl * decl = rd->getTypedefNameForAnonDecl(); if(decl) { thenamespace = &general; name = decl->getName(); } else { name = "anon"; } } assert(name != ""); if(!thenamespace->obj(name.c_str(),tt)) { //create new blank struct, fill in with members std::stringstream ss; ss << (rd->isStruct() ? "struct." : "union.") << name; PushTypeFunction("getorcreatecstruct"); lua_pushstring(L, name.c_str()); lua_pushstring(L,ss.str().c_str()); lua_call(L,2,1); tt->initFromStack(L,ref_table); tt->push(); thenamespace->setfield(name.c_str()); //register the type (this prevents an infinite loop for recursive types) } if(tt->boolean("undefined") && rd->getDefinition() != NULL) { tt->clearfield("undefined"); RecordDecl * defn = rd->getDefinition(); Obj entries; tt->newlist(&entries); if(GetFields(defn, &entries)) { if(!defn->isUnion()) { //structtype.entries = {entry1, entry2, ... } entries.push(); tt->setfield("entries"); } else { //add as a union: //structtype.entries = { {entry1,entry2,...} } Obj allentries; tt->obj("entries",&allentries); entries.push(); allentries.addentry(); } tt->pushfield("complete"); tt->push(); lua_call(L,1,0); } } if(fullname) { std::stringstream ss; if(thenamespace == &tagged) ss << (rd->isStruct() ? "struct " : "union "); ss << name; *fullname = ss.str(); } return true; } else { return ImportError("non-struct record types are not supported"); } }