It looks like we forgot to document this builtin. Can some documentation be added?
On Tue, 10 Apr 2018 at 15:01, Aaron Ballman via cfe-commits < cfe-commits@lists.llvm.org> wrote: > Author: aaronballman > Date: Tue Apr 10 14:58:13 2018 > New Revision: 329762 > > URL: http://llvm.org/viewvc/llvm-project?rev=329762&view=rev > Log: > Introduce a new builtin, __builtin_dump_struct, that is useful for dumping > structure contents at runtime in circumstances where debuggers may not be > easily available (such as in kernel work). > > Patch by Paul Semel. > > Added: > cfe/trunk/test/CodeGen/dump-struct-builtin.c > cfe/trunk/test/Sema/builtin-dump-struct.c > Modified: > cfe/trunk/include/clang/Basic/Builtins.def > cfe/trunk/lib/CodeGen/CGBuiltin.cpp > cfe/trunk/lib/Sema/SemaChecking.cpp > > Modified: cfe/trunk/include/clang/Basic/Builtins.def > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.def?rev=329762&r1=329761&r2=329762&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Basic/Builtins.def (original) > +++ cfe/trunk/include/clang/Basic/Builtins.def Tue Apr 10 14:58:13 2018 > @@ -1374,6 +1374,7 @@ BUILTIN(__builtin_addressof, "v*v&", "nc > BUILTIN(__builtin_operator_new, "v*z", "tc") > BUILTIN(__builtin_operator_delete, "vv*", "tn") > 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") > > Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=329762&r1=329761&r2=329762&view=diff > > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Tue Apr 10 14:58:13 2018 > @@ -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 @@ EmitCheckedMixedSignMultiply(CodeGenFunc > return RValue::get(Overflow); > } > > +static llvm::Value *dumpRecord(CodeGenFunction &CGF, QualType RType, > + Value *&RecordPtr, CharUnits Align, Value > *Func, > + int Lvl) { > + const auto *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 (RD->isUnion()) > + FieldPtr = CGF.Builder.CreatePointerCast( > + FieldPtr, > CGF.ConvertType(Context.getPointerType(FD->getType()))); > + else > + FieldPtr = CGF.Builder.CreateStructGEP(CGF.ConvertType(RType), > FieldPtr, > + FD->getFieldIndex()); > + > + GString = CGF.Builder.CreateGlobalStringPtr( > + llvm::Twine(Pad) > + .concat(FD->getType().getAsString()) > + .concat(llvm::Twine(' ')) > + .concat(FD->getNameAsString()) > + .concat(" : ") > + .str()); > + 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()) { > + Value *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 > + llvm::Twine Format = Types.find(CanonicalType) == Types.end() > + ? Types[Context.VoidPtrTy] > + : Types[CanonicalType]; > + > + Address FieldAddress = Address(FieldPtr, Align); > + FieldPtr = CGF.Builder.CreateLoad(FieldAddress); > + > + // FIXME Need to handle bitfield here > + GString = CGF.Builder.CreateGlobalStringPtr( > + Format.concat(llvm::Twine('\n')).str()); > + TmpRes = CGF.Builder.CreateCall(Func, {GString, FieldPtr}); > + Res = CGF.Builder.CreateAdd(Res, TmpRes); > + } > + > + GString = CGF.Builder.CreateGlobalStringPtr(Pad + "}\n"); > + 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 @@ RValue CodeGenFunction::EmitBuiltinExpr( > 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: > > Modified: cfe/trunk/lib/Sema/SemaChecking.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=329762&r1=329761&r2=329762&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) > +++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Apr 10 14:58:13 2018 > @@ -1105,6 +1105,63 @@ Sema::CheckBuiltinFunctionCall(FunctionD > CorrectDelayedTyposInExpr(TheCallResult.get()); > return Res; > } > + 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() || > + !PtrArgType->getPointeeType()->isRecordType()) { > + Diag(PtrArg->getLocStart(), > diag::err_typecheck_convert_incompatible) > + << PtrArgType << "structure pointer" << 1 << 0 << 3 << 1 << > PtrArgType > + << "structure pointer"; > + 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()) { > + Diag(FnPtrArg->getLocStart(), > diag::err_typecheck_convert_incompatible) > + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 > + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; > + return ExprError(); > + } > + > + const auto *FuncType = > + FnPtrArgType->getPointeeType()->getAs<FunctionType>(); > + > + if (!FuncType) { > + Diag(FnPtrArg->getLocStart(), > diag::err_typecheck_convert_incompatible) > + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 > + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; > + return ExprError(); > + } > + > + if (const auto *FT = dyn_cast<FunctionProtoType>(FuncType)) { > + if (!FT->getNumParams()) { > + Diag(FnPtrArg->getLocStart(), > diag::err_typecheck_convert_incompatible) > + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 > << 3 > + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; > + return ExprError(); > + } > + QualType PT = FT->getParamType(0); > + if (!FT->isVariadic() || FT->getReturnType() != Context.IntTy || > + !PT->isPointerType() || !PT->getPointeeType()->isCharType() || > + !PT->getPointeeType().isConstQualified()) { > + 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 > case Builtin::BI__builtin___memcpy_chk: > > Added: cfe/trunk/test/CodeGen/dump-struct-builtin.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/dump-struct-builtin.c?rev=329762&view=auto > > ============================================================================== > --- cfe/trunk/test/CodeGen/dump-struct-builtin.c (added) > +++ cfe/trunk/test/CodeGen/dump-struct-builtin.c Tue Apr 10 14:58:13 2018 > @@ -0,0 +1,391 @@ > +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm %s -o - | > FileCheck %s > + > +#include "Inputs/stdio.h" > + > +int printf(const char *fmt, ...) { > + return 0; > +} > + > +void unit1() { > + struct U1A { > + short a; > + }; > + > + struct U1A a = { > + .a = 12, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U1A, > %struct.U1A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i16, i16* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i16 [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit2() { > + struct U2A { > + unsigned short a; > + }; > + > + struct U2A a = { > + .a = 12, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U2A, > %struct.U2A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i16, i16* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i16 [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit3() { > + struct U3A { > + int a; > + }; > + > + struct U3A a = { > + .a = 12, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U3A, > %struct.U3A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i32, i32* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit4() { > + struct U4A { > + unsigned int a; > + }; > + > + struct U4A a = { > + .a = 12, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U4A, > %struct.U4A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i32, i32* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit5() { > + struct U5A { > + long a; > + }; > + > + struct U5A a = { > + .a = 12, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U5A, > %struct.U5A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i64, i64* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i64 [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit6() { > + struct U6A { > + unsigned long a; > + }; > + > + struct U6A a = { > + .a = 12, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U6A, > %struct.U6A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i64, i64* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i64 [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit7() { > + struct U7A { > + long long a; > + }; > + > + struct U7A a = { > + .a = 12, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U7A, > %struct.U7A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i64, i64* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i64 [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit8() { > + struct U8A { > + long long a; > + }; > + > + struct U8A a = { > + .a = 12, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U8A, > %struct.U8A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i64, i64* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i64 [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit9() { > + struct U9A { > + char a; > + }; > + > + struct U9A a = { > + .a = 'a', > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U9A, > %struct.U9A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i8, i8* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i8 [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit10() { > + struct U10A { > + char *a; > + }; > + > + struct U10A a = { > + .a = "LSE", > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U10A, > %struct.U10A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i8*, i8** [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i8* [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit11() { > + struct U11A { > + void *a; > + }; > + > + struct U11A a = { > + .a = (void *)0x12345678, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U11A, > %struct.U11A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i8*, i8** [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i8* [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit12() { > + struct U12A { > + const char *a; > + }; > + > + struct U12A a = { > + .a = "LSE", > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U12A, > %struct.U12A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i8*, i8** [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i8* [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit13() { > + typedef char *charstar; > + struct U13A { > + const charstar a; > + }; > + > + struct U13A a = { > + .a = "LSE", > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U13A, > %struct.U13A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i8*, i8** [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i8* [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit14() { > + struct U14A { > + double a; > + }; > + > + struct U14A a = { > + .a = 1.123456, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U14A, > %struct.U14A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load double, double* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, double [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void unit15() { > + struct U15A { > + int a[3]; > + }; > + > + struct U15A a = { > + .a = {1, 2, 3}, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U15A, > %struct.U15A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load [3 x i32], [3 x i32]* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, [3 x i32] [[LOAD1]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void test1() { > + struct T1A { > + int a; > + char *b; > + }; > + > + struct T1A a = { > + .a = 12, > + .b = "LSE", > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.T1A, > %struct.T1A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i32, i32* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[LOAD1]]) > + // CHECK: [[RES2:%[0-9]+]] = getelementptr inbounds %struct.T1A, > %struct.T1A* %a, i32 0, i32 1 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD2:%[0-9]+]] = load i8*, i8** [[RES2]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i8* [[LOAD2]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void test2() { > + struct T2A { > + int a; > + }; > + > + struct T2B { > + int b; > + struct T2A a; > + }; > + > + struct T2B b = { > + .b = 24, > + .a = { > + .a = 12, > + } > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.T2B, > %struct.T2B* %b, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD1:%[0-9]+]] = load i32, i32* [[RES1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[LOAD1]]) > + // CHECK: [[NESTED_STRUCT:%[0-9]+]] = getelementptr inbounds > %struct.T2B, %struct.T2B* %b, i32 0, i32 1 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES2:%[0-9]+]] = getelementptr inbounds %struct.T2A, > %struct.T2A* [[NESTED_STRUCT]], i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[LOAD2:%[0-9]+]] = load i32, i32* [[RES2]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[LOAD2]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&b, &printf); > +} > + > +void test3() { > + struct T3A { > + union { > + int a; > + char b[4]; > + }; > + }; > + > + struct T3A a = { > + .a = 42, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.T3A, > %struct.T3A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[BC1:%[0-9]+]] = bitcast %union.anon* [[RES1]] to i32* > + // CHECK: [[LOAD1:%[0-9]+]] = load i32, i32* [[BC1]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[LOAD1]]) > + // CHECK: [[BC2:%[0-9]+]] = bitcast %union.anon* [[RES1]] to [4 x i8]* > + // CHECK: [[LOAD2:%[0-9]+]] = load [4 x i8], [4 x i8]* [[BC2]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, [4 x i8] [[LOAD2]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > + > +void test4() { > + struct T4A { > + union { > + struct { > + void *a; > + }; > + struct { > + unsigned long b; > + }; > + }; > + }; > + > + struct T4A a = { > + .a = (void *)0x12345678, > + }; > + > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.T4A, > %struct.T4A* %a, i32 0, i32 0 > + // CHECK: call i32 (i8*, ...) @printf( > + // CHECK: [[BC1:%[0-9]+]] = bitcast %union.anon.0* [[RES1]] to > %struct.anon* > + // CHECK: [[RES2:%[0-9]+]] = getelementptr inbounds %struct.anon, > %struct.anon* [[BC1]], i32 0, i32 0 > + // CHECK: [[LOAD1:%[0-9]+]] = load i8*, i8** [[RES2]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i8* [[LOAD1]]) > + > + // CHECK: [[BC2:%[0-9]+]] = bitcast %union.anon.0* [[RES1]] to > %struct.anon.1* > + // CHECK: [[RES3:%[0-9]+]] = getelementptr inbounds %struct.anon.1, > %struct.anon.1* [[BC2]], i32 0, i32 0 > + // CHECK: [[LOAD2:%[0-9]+]] = load i64, i64* [[RES3]], > + // CHECK: call i32 (i8*, ...) @printf({{.*}}, i64 [[LOAD2]]) > + // CHECK: call i32 (i8*, ...) @printf( > + __builtin_dump_struct(&a, &printf); > +} > > Added: cfe/trunk/test/Sema/builtin-dump-struct.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/builtin-dump-struct.c?rev=329762&view=auto > > ============================================================================== > --- cfe/trunk/test/Sema/builtin-dump-struct.c (added) > +++ cfe/trunk/test/Sema/builtin-dump-struct.c Tue Apr 10 14:58:13 2018 > @@ -0,0 +1,42 @@ > +// RUN: %clang_cc1 -triple i386-unknown-unknown -fsyntax-only > -fno-spell-checking -verify %s > + > +void invalid_uses() { > + struct A { > + }; > + struct A a; > + void *b; > + int (*goodfunc)(const char *, ...); > + int (*badfunc1)(const char *); > + int (*badfunc2)(int, ...); > + void (*badfunc3)(const char *, ...); > + int (*badfunc4)(char *, ...); > + int (*badfunc5)(void); > + > + __builtin_dump_struct(); // expected-error {{too few > arguments to function call, expected 2, have 0}} > + __builtin_dump_struct(1); // expected-error {{too few > arguments to function call, expected 2, have 1}} > + __builtin_dump_struct(1, 2); // expected-error {{passing 'int' > to parameter of incompatible type structure pointer: type mismatch at 1st > parameter ('int' vs structure pointer)}} > + __builtin_dump_struct(&a, 2); // expected-error {{passing 'int' > to parameter of incompatible type 'int (*)(const char *, ...)': type > mismatch at 2nd parameter ('int' vs 'int (*)(const char *, ...)')}} > + __builtin_dump_struct(b, goodfunc); // expected-error {{passing 'void > *' to parameter of incompatible type structure pointer: type mismatch at > 1st parameter ('void *' vs structure pointer)}} > + __builtin_dump_struct(&a, badfunc1); // expected-error {{passing 'int > (*)(const char *)' to parameter of incompatible type 'int (*)(const char *, > ...)': type mismatch at 2nd parameter ('int (*)(const char *)' vs 'int > (*)(const char *, ...)')}} > + __builtin_dump_struct(&a, badfunc2); // expected-error {{passing 'int > (*)(int, ...)' to parameter of incompatible type 'int (*)(const char *, > ...)': type mismatch at 2nd parameter ('int (*)(int, ...)' vs 'int > (*)(const char *, ...)')}} > + __builtin_dump_struct(&a, badfunc3); // expected-error {{passing 'void > (*)(const char *, ...)' to parameter of incompatible type 'int (*)(const > char *, ...)': type mismatch at 2nd parameter ('void (*)(const char *, > ...)' vs 'int (*)(const char *, ...)')}} > + __builtin_dump_struct(&a, badfunc4); // expected-error {{passing 'int > (*)(char *, ...)' to parameter of incompatible type 'int (*)(const char *, > ...)': type mismatch at 2nd parameter ('int (*)(char *, ...)' vs 'int > (*)(const char *, ...)')}} > + __builtin_dump_struct(&a, badfunc5); // expected-error {{passing 'int > (*)(void)' to parameter of incompatible type 'int (*)(const char *, ...)': > type mismatch at 2nd parameter ('int (*)(void)' vs 'int (*)(const char *, > ...)')}} > + __builtin_dump_struct(a, goodfunc); // expected-error {{passing > 'struct A' to parameter of incompatible type structure pointer: type > mismatch at 1st parameter ('struct A' vs structure pointer)}} > +} > + > +void valid_uses() { > + struct A { > + }; > + union B { > + }; > + > + int (*goodfunc)(const char *, ...); > + int (*goodfunc2)(); > + struct A a; > + union B b; > + > + __builtin_dump_struct(&a, goodfunc); > + __builtin_dump_struct(&b, goodfunc); > + __builtin_dump_struct(&a, goodfunc2); > +} > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits