paulsemel updated this revision to Diff 137775. paulsemel added a comment. Added recursive type pretty-printing as suggested by Aaron.
Repository: rC Clang https://reviews.llvm.org/D44093 Files: include/clang/Basic/Builtins.def lib/CodeGen/CGBuiltin.cpp lib/Sema/SemaChecking.cpp
Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -1110,6 +1110,66 @@ // so ensure that they are declared. DeclareGlobalNewDelete(); break; + case Builtin::BI__builtin_dump_struct: { + // We first want to ensure we are called with 2 arguments + if (checkArgCount(*this, TheCall, 2)) + return ExprError(); + // Ensure that the first argument is of type 'struct XX *' + const Expr *PtrArg = TheCall->getArg(0)->IgnoreParenImpCasts(); + const QualType PtrArgType = PtrArg->getType(); + if (!PtrArgType->isPointerType()) { + this->Diag(PtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << PtrArgType << "\'structure pointer type\'" + << 1 << 0 << 3 << 1 + << PtrArgType << "\'structure pointer type\'"; + return ExprError(); + } + + const RecordType *RT = PtrArgType->getPointeeType()->getAs<RecordType>(); + if (!RT) { + this->Diag(PtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << PtrArgType << "\'structure pointer type\'" + << 1 << 0 << 3 << 1 + << PtrArgType << "\'structure pointer type\'"; + return ExprError(); + } + // Ensure that the second argument is of type 'FunctionType' + const Expr *FnPtrArg = TheCall->getArg(1)->IgnoreImpCasts(); + const QualType FnPtrArgType = FnPtrArg->getType(); + if (!FnPtrArgType->isPointerType()) { + this->Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "\'int (*)(const char *, ...)\'" + << 1 << 0 << 3 << 2 + << FnPtrArgType << "\'int (*)(const char *, ...)\'"; + return ExprError(); + } + + const FunctionType *FuncType = + FnPtrArgType->getPointeeType()->getAs<FunctionType>(); + + if (!FuncType) { + this->Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "\'int (*)(const char *, ...)\'" + << 1 << 0 << 3 << 2 + << FnPtrArgType << "\'int (*)(const char *, ...)\'"; + return ExprError(); + } + + const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FuncType); + if (FT) { + if (!FT->isVariadic() || + FT->getReturnType() != Context.IntTy) { + this->Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType<< "\'int (*)(const char *, ...)\'" + << 1 << 0 << 3 << 2 + << FnPtrArgType << "\'int (*)(const char *, ...)\'"; + return ExprError(); + } + } + + TheCall->setType(Context.IntTy); + break; + } // check secure string manipulation functions where overflows // are detectable at compile time Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -14,6 +14,7 @@ #include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGOpenCLRuntime.h" +#include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" @@ -930,6 +931,93 @@ return RValue::get(Overflow); } +static Value *dumpRecord(CodeGenFunction &CGF, QualType RType, + Value*& RecordPtr, CharUnits Align, + Value *Func, int Lvl) +{ + const RecordType *RT = RType->getAs<RecordType>(); + ASTContext& Context = CGF.getContext(); + RecordDecl *RD = RT->getDecl()->getDefinition(); + ASTContext& Ctx = RD->getASTContext(); + const ASTRecordLayout &RL = Ctx.getASTRecordLayout(RD); + std::string Pad = std::string(Lvl * 4, ' '); + + Value *GString = CGF.Builder.CreateGlobalStringPtr(RType.getAsString() + + " {\n"); + Value *Res = CGF.Builder.CreateCall(Func, {GString}); + + static llvm::DenseMap<QualType, const char *> Types; + if (Types.empty()) { + Types[Context.CharTy] = "%c"; + Types[Context.BoolTy] = "%d"; + Types[Context.IntTy] = "%d"; + Types[Context.UnsignedIntTy] = "%u"; + Types[Context.LongTy] = "%ld"; + Types[Context.UnsignedLongTy] = "%lu"; + Types[Context.LongLongTy] = "%lld"; + Types[Context.UnsignedLongLongTy] = "%llu"; + Types[Context.ShortTy] = "%hd"; + Types[Context.UnsignedShortTy] = "%hu"; + Types[Context.VoidPtrTy] = "%p"; + Types[Context.FloatTy] = "%f"; + Types[Context.DoubleTy] = "%f"; + Types[Context.LongDoubleTy] = "%Lf"; + Types[Context.getPointerType(Context.CharTy)] = "%s"; + } + + for (const auto *FD : RD->fields()) { + uint64_t Off = RL.getFieldOffset(FD->getFieldIndex()); + Off = Ctx.toCharUnitsFromBits(Off).getQuantity(); + + Value *FieldPtr = RecordPtr; + if (Off) { + FieldPtr = CGF.Builder.CreatePtrToInt(FieldPtr, CGF.IntPtrTy); + FieldPtr = CGF.Builder.CreateAdd(FieldPtr, ConstantInt::get(CGF.IntPtrTy, Off)); + FieldPtr = CGF.Builder.CreateIntToPtr(FieldPtr, CGF.VoidPtrTy); + } + std::string Format = FD->getType().getAsString() + std::string(" ") + + FD->getNameAsString() + " : "; + + GString = CGF.Builder.CreateGlobalStringPtr(Pad + Format); + Value *TmpRes = CGF.Builder.CreateCall(Func, {GString}); + Res = CGF.Builder.CreateAdd(Res, TmpRes); + + QualType CanonicalType = + FD->getType().getUnqualifiedType().getCanonicalType(); + + // We check whether we are in a recursive type + if (CanonicalType->isRecordType()) { + TmpRes = dumpRecord(CGF, CanonicalType, FieldPtr, Align, Func, Lvl + 1); + Res = CGF.Builder.CreateAdd(TmpRes, Res); + continue; + } + + // We try to determine the best format to print the current field + if (Types.find(CanonicalType) == Types.end()) + Format = Types[Context.VoidPtrTy]; + else + Format = Types[CanonicalType]; + + QualType ResPtrType = Context.getPointerType(FD->getType()); + llvm::Type *ResType = CGF.ConvertType(ResPtrType); + FieldPtr = CGF.Builder.CreatePointerCast(FieldPtr, ResType); + Address FieldAddress = Address(FieldPtr, Align); + FieldPtr = CGF.Builder.CreateLoad(FieldAddress); + + // FIXME Need to handle bitfield here + + GString = CGF.Builder.CreateGlobalStringPtr(Format + "\n"); + TmpRes = CGF.Builder.CreateCall(Func, {GString, FieldPtr}); + Res = CGF.Builder.CreateAdd(Res, TmpRes); + } + + std::string Format = "}\n"; + GString = CGF.Builder.CreateGlobalStringPtr(Pad + Format); + Value *TmpRes = CGF.Builder.CreateCall(Func, {GString}); + Res = CGF.Builder.CreateAdd(Res, TmpRes); + return Res; +} + RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { @@ -1196,6 +1284,18 @@ return RValue::get(ComplexVal.first); } + case Builtin::BI__builtin_dump_struct: { + Value *Func = EmitScalarExpr(E->getArg(1)->IgnoreImpCasts()); + CharUnits Arg0Align = EmitPointerWithAlignment(E->getArg(0)).getAlignment(); + + const Expr *Arg0 = E->getArg(0)->IgnoreImpCasts(); + QualType Arg0Type = Arg0->getType()->getPointeeType(); + + Value *RecordPtr = EmitScalarExpr(Arg0); + Value *Res = dumpRecord(*this, Arg0Type, RecordPtr, Arg0Align, Func, 0); + return RValue::get(Res); + } + case Builtin::BI__builtin_cimag: case Builtin::BI__builtin_cimagf: case Builtin::BI__builtin_cimagl: Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -1374,6 +1374,7 @@ BUILTIN(__builtin_operator_new, "v*z", "c") BUILTIN(__builtin_operator_delete, "vv*", "n") BUILTIN(__builtin_char_memchr, "c*cC*iz", "n") +BUILTIN(__builtin_dump_struct, "ivC*v*", "tn") // Safestack builtins BUILTIN(__builtin___get_unsafe_stack_start, "v*", "Fn")
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits