The purpose of this new builtin is to be able to pretty print any structure at runtime.
This might be really useful when debugging is not an option or is fastidious (like for kernel development).
Details
- Reviewers
aaron.ballman echristo rsmith arichardson
Diff Detail
- Repository
- rC Clang
Event Timeline
Adding some reviewers.
One thing that's missing from this patch are test cases that demonstrate both the semantic checking (builtin accepts proper args, rejects improper ones, etc) and output.
lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
1204–1205 | These declarations do not meet our coding style guidelines -- you should pick some new names (elsewhere as well). | |
1208 | I don't see anything enforcing this constraint, so users are likely to hit this assertion rather than a compile error. | |
1211 | Please don't use auto when the type is not explicitly spelled out in the initializer. | |
1218–1232 | These should only be set up one time rather than each time someone calls the builtin. | |
1235–1236 | Can be replaced with a range-based for loop over fields(). Also, the formatting of the braces doesn't match the coding standard (happens elsewhere as well) -- you should run your patch through clang-format: https://clang.llvm.org/docs/ClangFormat.html#script-for-patch-reformatting | |
1258 | Are you intending to implement this as part of this functionality? |
lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
1208 | I actually didn't manage to enforce this in the builtin declaration as we can only declare simple types (I am probably missing something) | |
1258 | Yes, my goal is to be able to dump the bitfields correctly, particularly if the structure is packed (for dumping a GDT for example). |
lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
1206 | You can use const auto * here because the type is spelled out in the initializer. | |
1208 | I think this builtin will require custom type checking (so its signature needs a t), and then you can add your code to Sema::CheckBuiltinFunctionCall() to do the actual semantic checking. | |
1211 | Please don't name the variable the same name as a type. | |
1231 | It's unfortunate that you cannot distinguish between float and double. Do you need to use the format specifiers exactly? What about other type information, like qualifiers or array extents? How should this handle types that do not exist in this mapping, like structure or enum types? | |
1238 | const auto * | |
1258 | Okay, this should probably be a FIXME comment if you don't intend to handle it in the initial patch. It should also have a test case with some comments about the test behavior. |
lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
1206 | After thinking about it, I find it clearer to spell the full type when possible (that's also probably because I'm used to code in C :) ) | |
1231 | So, I've think about it. What I am going to do is that if I do not know the type of the field, I am just going to print it as a pointer. I know that it is not the best solution, but I think it's a okay-ish solution until I implement the other types. |
include/clang/Basic/DiagnosticSemaKinds.td | ||
---|---|---|
5022–5023 | Can you look to see if we have an existing diagnostic that can cover this instead? | |
lib/CodeGen/CGBuiltin.cpp | ||
1218 | This seems insufficient, as there are other qualifiers (restrict, ObjC GC qualifiers, etc). I think a better way to do this is to call QualType::getUnqualifiedType() on the type accessing the map. | |
1231 |
Eek. That seems unfortunate. I'm thinking about very common use cases, like: struct S { int i, j; float x, y; }; struct T { struct S s; int k; }; Printing out s as a pointer seems... not particularly useful. | |
1252 | What about other types that have format specifiers (ptrdiff_t, size_t, intptr_t, char16_t, etc)? | |
1255 | I don't think this comment adds a lot of value. | |
1269–1270 | We generally prefer // style comments unless there's good reason to use /* */. | |
lib/Sema/SemaChecking.cpp | ||
1114 | Comments should be grammatically correct, including punctuation (here and elsewhere). | |
1118 | You probably want to use IgnoreParenImpCasts(). | |
1119 | Rather than calling is followed by get, you should just call get once and check the results here. | |
1121 | The string literals should be part of a %select in the diagnostic itself rather than printed this way. | |
1132–1133 | Same suggestions here. Also, Arg1 and Arg0 aren't particularly descriptive names. Can you pick names based on the semantics of the arguments rather than their position? | |
1135 | What is a "printf like function pointer type"? | |
1155 | Spurious newline. |
lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
1218 | Yes, I think you're totally right ! | |
1231 | Yes, I see that this is true for other types that I am not handling for the moment.. What do you think is the best behavior for those cases ? | |
1252 | So, for typedef, why not apply the QualType::getCanonicalType to our field type, so that we try to get rid of those intermediate typedefs ? | |
lib/Sema/SemaChecking.cpp | ||
1121 | So, I am now using an other diagnostic definition, so I am constrained to keep using string literals I think.. | |
1135 | I have changed this to the actual prototype of a "printf like" function so that it's way clearer of what I am expecting ! |
lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
1231 | I would probably try to recurse into the contained member with another layer of {} around its fields; if you restructured the code such that it is a function, this recursion probably wouldn't be too bad to implement. | |
1252 | It should be possible to do for type aliases, because you know the canonical type information. However, that won't work for builtin types that aren't a typedef like char16_t. |
lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
1252 | Sure, but in this case, the only soluntion is to determine how we want to print those builtins and add those and the static map |
Thanks for working on this! Few remarks in the comments.
lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
934 | llvm::Value for consistency? | |
966 | Indentation failed here. | |
976 | I think you should use getelementptr instead of ptrtoint -> inttoptr https://llvm.org/docs/GetElementPtr.html | |
997 | Indentation failed here too. | |
1003 | If you use GEP you should be able to get rid of this cast here. | |
1009 | You can probably use llvm::Twine for the concatenation of Format: http://llvm.org/doxygen/classllvm_1_1Twine.html. | |
lib/Sema/SemaChecking.cpp | ||
1159 | if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FuncType)) |
BTW, as far as i can tell this still has zero test coverage (no new tests are being added).
I'd expect to see the tests for the actual output
- one struct per each type it is able to print
- probably some tests showing error handling,
and possibly the availability of the builtin is somehow tested, too?
Hi,
Sure, I am going to work on it, now that the patch seems to be kind of "Okay" for its first version !
Thanks !
Added some tests (unit tests for almost every types) and some other tests with tricky cases.
More tests are coming soon.
lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
935 | Formatting looks off here and elsewhere. You should run the patch through clang-format. https://clang.llvm.org/docs/ClangFormat.html#script-for-patch-reformatting | |
938 | Can use const auto * rather than spelling the type twice. | |
lib/Sema/SemaChecking.cpp | ||
1128 | const auto * | |
1129 | I'd hoist this test to avoid duplicated code. if (!PtrArgType->isPointerType() || !PtrArgType->getPointeeType()->isRecordType()) | |
1147–1148 | const auto * | |
1158 | const auto * | |
1159–1160 | You should also check that the first argument is const char * and add test cases for when it's not. |
lib/Sema/SemaChecking.cpp | ||
---|---|---|
1122 | Drop all instances of this->. | |
1156 | Rather than building up a type only for comparison purposes, why not check: QualType PT = FT->getParamType(0); if (!PT->isPointerType() || !PT->getPointeeType()->isCharType() || !PT->getPointeeType().isConstQualified()) { Diag(...); } | |
test/CodeGen/dump-struct-builtin.c | ||
254 ↗ | (On Diff #138832) | I'd like to see some test cases using unions (perhaps mixing unions and inner struct types), tests using arrays, floating-point values, and type qualifiers on the data members. |
test/Sema/builtin-dump-struct.c | ||
8 ↗ | (On Diff #138832) | Can you also add a test for: int (*badfunc4)(char *, ...); and int (*badfunc5)(); |
15 ↗ | (On Diff #138832) | Hrm, the 'structure pointer type' in this diagnostic is unfortunate because it's being quoted as though it were a real type -- you could drop the single quotes. If you think the resulting diagnostic reads too strangely, perhaps we will have to go back to a custom diagnostic after all. |
17 ↗ | (On Diff #138832) | Why &goodfunc? |
test/Sema/builtin-dump-struct.c | ||
---|---|---|
8 ↗ | (On Diff #138832) | Isn't int (*func)() is a valid prototype for a printf like function in C ? |
15 ↗ | (On Diff #138832) | I think it will be better to just put something like structure pointer, so that we understand the type we are talking about. |
17 ↗ | (On Diff #138832) | Yes, we already have a test like this anyway :) |
Added Aaron suggestions.
Fixed a bug when having nested anonymous unions and structures.
Sorry for the delayed review; I'm back from vacation now and am picking things up again.
test/Sema/builtin-dump-struct.c | ||
---|---|---|
8 ↗ | (On Diff #138832) |
No, because it's missing the const char * as the mandatory first parameter. Do you want that to be allowed and hope the callee has it correct on their side, or do you want it to diagnose as not being a valid function? |
15 ↗ | (On Diff #138832) | I think it's fine now; if it turns out to be horribly confusing to users, we can address it later. |
17 ↗ | (On Diff #138832) | It was more a question of why the ampersand on the second argument -- I think that can be dropped and it'll be consistent with the rest of the tests. |
No problem, thanks for getting back on this ! I was busy because of my midterms anyway :)
test/Sema/builtin-dump-struct.c | ||
---|---|---|
8 ↗ | (On Diff #138832) | Actually, from a kernel developer perspective, I would say it's better to let the user do its stuff on his side, because kernel is full of trick ! |
17 ↗ | (On Diff #138832) | Sure, sorry, I missed this. Totally agree with you, I am going to make the changes. |
Updated the amperstamp in the Sema test to be consistent with the remaining part of it.
test/Sema/builtin-dump-struct.c | ||
---|---|---|
8 ↗ | (On Diff #138832) | Okay, if you think it'd be beneficial to allow a function without a prototype, I'm okay with it. Can you make it an explicit "good" test case? |
test/Sema/builtin-dump-struct.c | ||
---|---|---|
8 ↗ | (On Diff #138832) | Sure :) |
Added a good test for the int (*)() function prototype, as we decided to accept it as a valid function for the dumper
I'm also often restricted to using printf for debugging so this looks really useful!
However, before committing this I feel like the test should also verify that the format strings that are generated are sensible.
Also what should happens when you have enum members in your struct or maybe even C++ pointers to members?
test/Sema/builtin-dump-struct.c | ||
---|---|---|
42 ↗ | (On Diff #141762) | I think there should also be a test here that we get an error when the struct contains bitfields instead of crashing/generating nonsense in CodeGen. |
So, for the moment, we are only handling basic types. That said, for the enum in C, we will print according to the type of the enum.
In the future versions, I really want to be able to print the name of the enum so that the output is more relevent.
Anyway, the rule I followed for the moment is : if I don't recognize the type, I print it as an address.
test/Sema/builtin-dump-struct.c | ||
---|---|---|
42 ↗ | (On Diff #141762) | Do you really think that I should throw an error just because there is a bitfield ? |
So, for the moment, we are only handling basic types. That said, for the enum in C, we will print according to the type of the enum.
In the future versions, I really want to be able to print the name of the enum so that the output is more relevent.
Anyway, the rule I followed for the moment is : if I don't recognize the type, I print it as an address.
I you just print the address for unrecognized types then that should be fine. Thanks
test/Sema/builtin-dump-struct.c | ||
---|---|---|
42 ↗ | (On Diff #141762) | I would prefer an error instead of incorrect output since that can result in lots of unncessary debug work/false conclusions. But as long as it gets fixed/turned into an error before the final 7.0 release I think it shouldn't matter. |
I don't really know what's the procedure right now.. What should I do once you both accepted the patch ? :)
You're good to commit the patch and address the concerns raised by @arichardson in a follow-up patch. Do you need someone to commit on your behalf?
Can you rebase the patch? The patch did not apply cleanly for me against trunk (the contents of the check function are appearing in CheckARMBuiltinExclusiveCall()).
(Also, one tiny nit about escaped characters that can be fixed at the same time.)
lib/Sema/SemaChecking.cpp | ||
---|---|---|
1133 | Minor nit: can you remove the escape character for the single quotes (here and elsewhere in the patch), as there's no need to escape that character? |
Thank you for rebasing, but the patch does not pass tests locally for me. I get the following results (testing on Windows x64 with MSVC 2017 in a Debug build):
63>**** TEST 'Clang :: CodeGen/dump-struct-builtin.c' FAILED ****
63>Script:
63>--
63>d:\build\debug\bin\clang.EXE -cc1 -internal-isystem d:\build\debug\lib\clang\7.0.0\include -nostdsysteminc -emit-llvm D:\llvm\tools\clang\test\CodeGen\dump-struct-builtin.c -o - | D:\build\Debug\bin\FileCheck.EXE D:\llvm\tools\clang\test\CodeGen\dump-struct-builtin.c
63>--
63>Exit Code: 1
63>
63>Command Output (stdout):
63>--
63>$ "d:\build\debug\bin\clang.EXE" "-cc1" "-internal-isystem" "d:\build\debug\lib\clang\7.0.0\include" "-nostdsysteminc" "-emit-llvm" "D:\llvm\tools\clang\test\CodeGen\dump-struct-builtin.c" "-o" "-"
63># command stderr:
63>D:\llvm\tools\clang\test\CodeGen\dump-struct-builtin.c(20,30): warning G4AB12AC8: implicitly declaring library function 'printf' with type 'int (const char *, ...)'
63>
63> __builtin_dump_struct(&a, &printf);
63>
63> ^
63>
63>D:\llvm\tools\clang\test\CodeGen\dump-struct-builtin.c:20:30: note: include the header <stdio.h> or explicitly provide a declaration for 'printf'
63>
63>1 warning generated.
63>
63>
63>$ "D:\build\Debug\bin\FileCheck.EXE" "D:\llvm\tools\clang\test\CodeGen\dump-struct-builtin.c"
63># command stderr:
63>D:\llvm\tools\clang\test\CodeGen\dump-struct-builtin.c(105,12): error G8E235623: expected string not found in input
63>
63> // CHECK: [[RES1:%[0-9]+]] = getelementptr inbounds %struct.U6A, %struct.U6A* %a, i32 0, i32 0
63>
63> ^
63>
63><stdin>:290:35: note: scanning from here
63>
63> %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @28, i32 0, i32 0))
63>
63> ^
63>
63><stdin>:291:2: note: possible intended match here
63>
63> %2 = getelementptr inbounds %struct.U8A, %struct.U8A* %a, i32 0, i32 0
63>
63> ^
63>
63>
63>CUSTOMBUILD : error : command failed with exit status: 1
63>
63>--
63>
63>****
The output from the test on my machine is:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional>d:\build\debug\bin\clang.EXE -cc1 -internal-isystem d:\build\debug\lib\clang\7.0.0\include -nostdsysteminc -emit-llvm D:\llvm\tools\clang\test\CodeGen\dump-struct-builtin.c -o -
D:\llvm\tools\clang\test\CodeGen\dump-struct-builtin.c:20:30: warning: implicitly declaring library function 'printf' with type 'int (const char *, ...)'
__builtin_dump_struct(&a, &printf); ^
D:\llvm\tools\clang\test\CodeGen\dump-struct-builtin.c:20:30: note: include the header <stdio.h> or explicitly provide a declaration for 'printf'
; ModuleID = 'D:\llvm\tools\clang\test\CodeGen\dump-struct-builtin.c'
source_filename = "D:\5Cllvm\5Ctools\5Cclang\5Ctest\5CCodeGen\5Cdump-struct-builtin.c"
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
%struct.U1A = type { i16 }
%struct.U2A = type { i16 }
%struct.U3A = type { i32 }
%struct.U4A = type { i32 }
%struct.U5A = type { i32 }
%struct.U6A = type { i32 }
%struct.U7A = type { i64 }
%struct.U8A = type { i64 }
%struct.U9A = type { i8 }
%struct.U10A = type { i8* }
%struct.U11A = type { i8* }
%struct.U12A = type { i8* }
%struct.U13A = type { i8* }
%struct.U14A = type { double }
%struct.U15A = type { [3 x i32] }
%struct.T1A = type { i32, i8* }
%struct.T2B = type { i32, %struct.T2A }
%struct.T2A = type { i32 }
%struct.T3A = type { %union.anon }
%union.anon = type { i32 }
%struct.T4A = type { %union.anon.0 }
%union.anon.0 = type { %struct.anon }
%struct.anon = type { i8* }
%struct.anon.1 = type { i32 }
$"??_C@_03OMINOMMP@LSE?$AA@" = comdat any
@unit1.a = private unnamed_addr constant %struct.U1A { i16 12 }, align 2
@0 = private unnamed_addr constant [14 x i8] c"struct U1A {\0A\00"
@1 = private unnamed_addr constant [11 x i8] c"short a : \00"
@2 = private unnamed_addr constant [5 x i8] c"%hd\0A\00"
@3 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit2.a = private unnamed_addr constant %struct.U2A { i16 12 }, align 2
@4 = private unnamed_addr constant [14 x i8] c"struct U2A {\0A\00"
@5 = private unnamed_addr constant [20 x i8] c"unsigned short a : \00"
@6 = private unnamed_addr constant [5 x i8] c"%hu\0A\00"
@7 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit3.a = private unnamed_addr constant %struct.U3A { i32 12 }, align 4
@8 = private unnamed_addr constant [14 x i8] c"struct U3A {\0A\00"
@9 = private unnamed_addr constant [9 x i8] c"int a : \00"
@10 = private unnamed_addr constant [4 x i8] c"%d\0A\00"
@11 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit4.a = private unnamed_addr constant %struct.U4A { i32 12 }, align 4
@12 = private unnamed_addr constant [14 x i8] c"struct U4A {\0A\00"
@13 = private unnamed_addr constant [18 x i8] c"unsigned int a : \00"
@14 = private unnamed_addr constant [4 x i8] c"%u\0A\00"
@15 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit5.a = private unnamed_addr constant %struct.U5A { i32 12 }, align 4
@16 = private unnamed_addr constant [14 x i8] c"struct U5A {\0A\00"
@17 = private unnamed_addr constant [10 x i8] c"long a : \00"
@18 = private unnamed_addr constant [5 x i8] c"%ld\0A\00"
@19 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit6.a = private unnamed_addr constant %struct.U6A { i32 12 }, align 4
@20 = private unnamed_addr constant [14 x i8] c"struct U6A {\0A\00"
@21 = private unnamed_addr constant [19 x i8] c"unsigned long a : \00"
@22 = private unnamed_addr constant [5 x i8] c"%lu\0A\00"
@23 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit7.a = private unnamed_addr constant %struct.U7A { i64 12 }, align 8
@24 = private unnamed_addr constant [14 x i8] c"struct U7A {\0A\00"
@25 = private unnamed_addr constant [15 x i8] c"long long a : \00"
@26 = private unnamed_addr constant [6 x i8] c"%lld\0A\00"
@27 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit8.a = private unnamed_addr constant %struct.U8A { i64 12 }, align 8
@28 = private unnamed_addr constant [14 x i8] c"struct U8A {\0A\00"
@29 = private unnamed_addr constant [15 x i8] c"long long a : \00"
@30 = private unnamed_addr constant [6 x i8] c"%lld\0A\00"
@31 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit9.a = private unnamed_addr constant %struct.U9A { i8 97 }, align 1
@32 = private unnamed_addr constant [14 x i8] c"struct U9A {\0A\00"
@33 = private unnamed_addr constant [10 x i8] c"char a : \00"
@34 = private unnamed_addr constant [4 x i8] c"%c\0A\00"
@35 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@"??_C@_03OMINOMMP@LSE?$AA@" = linkonce_odr dso_local unnamed_addr constant [4 x i8] c"LSE\00", comdat, align 1
@unit10.a = private unnamed_addr constant %struct.U10A { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"??_C@_03OMINOMMP@LSE?$AA@", i32 0, i32 0) }, align 8
@36 = private unnamed_addr constant [15 x i8] c"struct U10A {\0A\00"
@37 = private unnamed_addr constant [12 x i8] c"char * a : \00"
@38 = private unnamed_addr constant [4 x i8] c"%s\0A\00"
@39 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit11.a = private unnamed_addr constant %struct.U11A { i8* inttoptr (i64 305419896 to i8*) }, align 8
@40 = private unnamed_addr constant [15 x i8] c"struct U11A {\0A\00"
@41 = private unnamed_addr constant [12 x i8] c"void * a : \00"
@42 = private unnamed_addr constant [4 x i8] c"%p\0A\00"
@43 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit12.a = private unnamed_addr constant %struct.U12A { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"??_C@_03OMINOMMP@LSE?$AA@", i32 0, i32 0) }, align 8
@44 = private unnamed_addr constant [15 x i8] c"struct U12A {\0A\00"
@45 = private unnamed_addr constant [18 x i8] c"const char * a : \00"
@46 = private unnamed_addr constant [4 x i8] c"%p\0A\00"
@47 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit13.a = private unnamed_addr constant %struct.U13A { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"??_C@_03OMINOMMP@LSE?$AA@", i32 0, i32 0) }, align 8
@48 = private unnamed_addr constant [15 x i8] c"struct U13A {\0A\00"
@49 = private unnamed_addr constant [20 x i8] c"const charstar a : \00"
@50 = private unnamed_addr constant [4 x i8] c"%s\0A\00"
@51 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit14.a = private unnamed_addr constant %struct.U14A { double 0x3FF1F9ACFFA7EB6C }, align 8
@52 = private unnamed_addr constant [15 x i8] c"struct U14A {\0A\00"
@53 = private unnamed_addr constant [12 x i8] c"double a : \00"
@54 = private unnamed_addr constant [4 x i8] c"%f\0A\00"
@55 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@unit15.a = private unnamed_addr constant %struct.U15A { [3 x i32] [i32 1, i32 2, i32 3] }, align 4
@56 = private unnamed_addr constant [15 x i8] c"struct U15A {\0A\00"
@57 = private unnamed_addr constant [13 x i8] c"int [3] a : \00"
@58 = private unnamed_addr constant [4 x i8] c"%p\0A\00"
@59 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@test1.a = private unnamed_addr constant %struct.T1A { i32 12, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"??_C@_03OMINOMMP@LSE?$AA@", i32 0, i32 0) }, align 8
@60 = private unnamed_addr constant [14 x i8] c"struct T1A {\0A\00"
@61 = private unnamed_addr constant [9 x i8] c"int a : \00"
@62 = private unnamed_addr constant [4 x i8] c"%d\0A\00"
@63 = private unnamed_addr constant [12 x i8] c"char * b : \00"
@64 = private unnamed_addr constant [4 x i8] c"%s\0A\00"
@65 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@test2.b = private unnamed_addr constant %struct.T2B { i32 24, %struct.T2A { i32 12 } }, align 4
@66 = private unnamed_addr constant [14 x i8] c"struct T2B {\0A\00"
@67 = private unnamed_addr constant [9 x i8] c"int b : \00"
@68 = private unnamed_addr constant [4 x i8] c"%d\0A\00"
@69 = private unnamed_addr constant [16 x i8] c"struct T2A a : \00"
@70 = private unnamed_addr constant [14 x i8] c"struct T2A {\0A\00"
@71 = private unnamed_addr constant [13 x i8] c" int a : \00"
@72 = private unnamed_addr constant [4 x i8] c"%d\0A\00"
@73 = private unnamed_addr constant [7 x i8] c" }\0A\00"
@74 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@test3.a = private unnamed_addr constant %struct.T3A { %union.anon { i32 42 } }, align 4
@75 = private unnamed_addr constant [14 x i8] c"struct T3A {\0A\00"
@76 = private unnamed_addr constant [91 x i8] c"union T3A::(anonymous at D:\5Cllvm\5Ctools\5Cclang\5Ctest\5CCodeGen\5Cdump-struct-builtin.c:334:5) : \00"
@77 = private unnamed_addr constant [90 x i8] c"union T3A::(anonymous at D:\5Cllvm\5Ctools\5Cclang\5Ctest\5CCodeGen\5Cdump-struct-builtin.c:334:5) {\0A\00"
@78 = private unnamed_addr constant [13 x i8] c" int a : \00"
@79 = private unnamed_addr constant [4 x i8] c"%d\0A\00"
@80 = private unnamed_addr constant [18 x i8] c" char [4] b : \00"
@81 = private unnamed_addr constant [4 x i8] c"%p\0A\00"
@82 = private unnamed_addr constant [7 x i8] c" }\0A\00"
@83 = private unnamed_addr constant [3 x i8] c"}\0A\00"
@test4.a = private unnamed_addr constant %struct.T4A { %union.anon.0 { %struct.anon { i8* inttoptr (i64 305419896 to i8*) } } }, align 8
@84 = private unnamed_addr constant [14 x i8] c"struct T4A {\0A\00"
@85 = private unnamed_addr constant [91 x i8] c"union T4A::(anonymous at D:\5Cllvm\5Ctools\5Cclang\5Ctest\5CCodeGen\5Cdump-struct-builtin.c:359:5) : \00"
@86 = private unnamed_addr constant [90 x i8] c"union T4A::(anonymous at D:\5Cllvm\5Ctools\5Cclang\5Ctest\5CCodeGen\5Cdump-struct-builtin.c:359:5) {\0A\00"
@87 = private unnamed_addr constant [96 x i8] c" struct T4A::(anonymous at D:\5Cllvm\5Ctools\5Cclang\5Ctest\5CCodeGen\5Cdump-struct-builtin.c:360:7) : \00"
@88 = private unnamed_addr constant [91 x i8] c"struct T4A::(anonymous at D:\5Cllvm\5Ctools\5Cclang\5Ctest\5CCodeGen\5Cdump-struct-builtin.c:360:7) {\0A\00"
@89 = private unnamed_addr constant [20 x i8] c" void * a : \00"
@90 = private unnamed_addr constant [4 x i8] c"%p\0A\00"
@91 = private unnamed_addr constant [11 x i8] c" }\0A\00"
@92 = private unnamed_addr constant [96 x i8] c" struct T4A::(anonymous at D:\5Cllvm\5Ctools\5Cclang\5Ctest\5CCodeGen\5Cdump-struct-builtin.c:363:7) : \00"
@93 = private unnamed_addr constant [91 x i8] c"struct T4A::(anonymous at D:\5Cllvm\5Ctools\5Cclang\5Ctest\5CCodeGen\5Cdump-struct-builtin.c:363:7) {\0A\00"
@94 = private unnamed_addr constant [27 x i8] c" unsigned long b : \00"
@95 = private unnamed_addr constant [5 x i8] c"%lu\0A\00"
@96 = private unnamed_addr constant [11 x i8] c" }\0A\00"
@97 = private unnamed_addr constant [7 x i8] c" }\0A\00"
@98 = private unnamed_addr constant [3 x i8] c"}\0A\00"
; Function Attrs: noinline nounwind optnone
define dso_local void @unit1() #0 {
entry:
%a = alloca %struct.U1A, align 2 %0 = bitcast %struct.U1A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 2 %0, i8* align 2 bitcast (%struct.U1A* @unit1.a to i8*), i64 2, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @0, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U1A, %struct.U1A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @1, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i16, i16* %2, align 2 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @2, i32 0, i32 0), i16 %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @3, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: argmemonly nounwind
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #1
declare dso_local i32 @printf(i8*, ...) #2
; Function Attrs: noinline nounwind optnone
define dso_local void @unit2() #0 {
entry:
%a = alloca %struct.U2A, align 2 %0 = bitcast %struct.U2A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 2 %0, i8* align 2 bitcast (%struct.U2A* @unit2.a to i8*), i64 2, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @4, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U2A, %struct.U2A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @5, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i16, i16* %2, align 2 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @6, i32 0, i32 0), i16 %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @7, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit3() #0 {
entry:
%a = alloca %struct.U3A, align 4 %0 = bitcast %struct.U3A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%struct.U3A* @unit3.a to i8*), i64 4, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @8, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U3A, %struct.U3A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @9, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i32, i32* %2, align 4 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @10, i32 0, i32 0), i32 %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @11, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit4() #0 {
entry:
%a = alloca %struct.U4A, align 4 %0 = bitcast %struct.U4A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%struct.U4A* @unit4.a to i8*), i64 4, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @12, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U4A, %struct.U4A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @13, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i32, i32* %2, align 4 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @14, i32 0, i32 0), i32 %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @15, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit5() #0 {
entry:
%a = alloca %struct.U5A, align 4 %0 = bitcast %struct.U5A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%struct.U5A* @unit5.a to i8*), i64 4, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @16, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U5A, %struct.U5A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @17, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i32, i32* %2, align 4 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @18, i32 0, i32 0), i32 %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @19, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit6() #0 {
entry:
%a = alloca %struct.U6A, align 4 %0 = bitcast %struct.U6A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%struct.U6A* @unit6.a to i8*), i64 4, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @20, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U6A, %struct.U6A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* @21, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i32, i32* %2, align 4 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @22, i32 0, i32 0), i32 %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @23, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit7() #0 {
entry:
%a = alloca %struct.U7A, align 8 %0 = bitcast %struct.U7A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %0, i8* align 8 bitcast (%struct.U7A* @unit7.a to i8*), i64 8, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @24, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U7A, %struct.U7A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @25, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i64, i64* %2, align 8 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @26, i32 0, i32 0), i64 %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @27, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit8() #0 {
entry:
%a = alloca %struct.U8A, align 8 %0 = bitcast %struct.U8A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %0, i8* align 8 bitcast (%struct.U8A* @unit8.a to i8*), i64 8, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @28, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U8A, %struct.U8A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @29, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i64, i64* %2, align 8 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @30, i32 0, i32 0), i64 %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @31, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit9() #0 {
entry:
%a = alloca %struct.U9A, align 1 %0 = bitcast %struct.U9A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%struct.U9A, %struct.U9A* @unit9.a, i32 0, i32 0), i64 1, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @32, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U9A, %struct.U9A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @33, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i8, i8* %2, align 1 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @34, i32 0, i32 0), i8 %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @35, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit10() #0 {
entry:
%a = alloca %struct.U10A, align 8 %0 = bitcast %struct.U10A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %0, i8* align 8 bitcast (%struct.U10A* @unit10.a to i8*), i64 8, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @36, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U10A, %struct.U10A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @37, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i8*, i8** %2, align 8 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @38, i32 0, i32 0), i8* %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @39, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit11() #0 {
entry:
%a = alloca %struct.U11A, align 8 %0 = bitcast %struct.U11A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %0, i8* align 8 bitcast (%struct.U11A* @unit11.a to i8*), i64 8, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @40, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U11A, %struct.U11A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @41, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i8*, i8** %2, align 8 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @42, i32 0, i32 0), i8* %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @43, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit12() #0 {
entry:
%a = alloca %struct.U12A, align 8 %0 = bitcast %struct.U12A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %0, i8* align 8 bitcast (%struct.U12A* @unit12.a to i8*), i64 8, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @44, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U12A, %struct.U12A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @45, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i8*, i8** %2, align 8 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @46, i32 0, i32 0), i8* %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @47, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit13() #0 {
entry:
%a = alloca %struct.U13A, align 8 %0 = bitcast %struct.U13A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %0, i8* align 8 bitcast (%struct.U13A* @unit13.a to i8*), i64 8, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @48, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U13A, %struct.U13A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @49, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i8*, i8** %2, align 8 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @50, i32 0, i32 0), i8* %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @51, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit14() #0 {
entry:
%a = alloca %struct.U14A, align 8 %0 = bitcast %struct.U14A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %0, i8* align 8 bitcast (%struct.U14A* @unit14.a to i8*), i64 8, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @52, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U14A, %struct.U14A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @53, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load double, double* %2, align 8 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @54, i32 0, i32 0), double %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @55, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @unit15() #0 {
entry:
%a = alloca %struct.U15A, align 4 %0 = bitcast %struct.U15A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%struct.U15A* @unit15.a to i8*), i64 12, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @56, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U15A, %struct.U15A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @57, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load [3 x i32], [3 x i32]* %2, align 4 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @58, i32 0, i32 0), [3 x i32] %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @59, i32 0, i32 0)) %9 = add i32 %7, %8 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @test1() #0 {
entry:
%a = alloca %struct.T1A, align 8 %0 = bitcast %struct.T1A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %0, i8* align 8 bitcast (%struct.T1A* @test1.a to i8*), i64 16, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @60, i32 0, i32 0)) %2 = getelementptr inbounds %struct.T1A, %struct.T1A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @61, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i32, i32* %2, align 8 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @62, i32 0, i32 0), i32 %5) %7 = add i32 %4, %6 %8 = getelementptr inbounds %struct.T1A, %struct.T1A* %a, i32 0, i32 1 %9 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @63, i32 0, i32 0)) %10 = add i32 %7, %9 %11 = load i8*, i8** %8, align 8 %12 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @64, i32 0, i32 0), i8* %11) %13 = add i32 %10, %12 %14 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @65, i32 0, i32 0)) %15 = add i32 %13, %14 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @test2() #0 {
entry:
%b = alloca %struct.T2B, align 4 %0 = bitcast %struct.T2B* %b to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%struct.T2B* @test2.b to i8*), i64 8, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @66, i32 0, i32 0)) %2 = getelementptr inbounds %struct.T2B, %struct.T2B* %b, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @67, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i32, i32* %2, align 4 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @68, i32 0, i32 0), i32 %5) %7 = add i32 %4, %6 %8 = getelementptr inbounds %struct.T2B, %struct.T2B* %b, i32 0, i32 1 %9 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @69, i32 0, i32 0)) %10 = add i32 %7, %9 %11 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @70, i32 0, i32 0)) %12 = getelementptr inbounds %struct.T2A, %struct.T2A* %8, i32 0, i32 0 %13 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @71, i32 0, i32 0)) %14 = add i32 %11, %13 %15 = load i32, i32* %12, align 4 %16 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @72, i32 0, i32 0), i32 %15) %17 = add i32 %14, %16 %18 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @73, i32 0, i32 0)) %19 = add i32 %17, %18 %20 = add i32 %19, %10 %21 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @74, i32 0, i32 0)) %22 = add i32 %20, %21 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @test3() #0 {
entry:
%a = alloca %struct.T3A, align 4 %0 = bitcast %struct.T3A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%struct.T3A* @test3.a to i8*), i64 4, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @75, i32 0, i32 0)) %2 = getelementptr inbounds %struct.T3A, %struct.T3A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([91 x i8], [91 x i8]* @76, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([90 x i8], [90 x i8]* @77, i32 0, i32 0)) %6 = bitcast %union.anon* %2 to i32* %7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @78, i32 0, i32 0)) %8 = add i32 %5, %7 %9 = load i32, i32* %6, align 4 %10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @79, i32 0, i32 0), i32 %9) %11 = add i32 %8, %10 %12 = bitcast %union.anon* %2 to [4 x i8]* %13 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @80, i32 0, i32 0)) %14 = add i32 %11, %13 %15 = load [4 x i8], [4 x i8]* %12, align 4 %16 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @81, i32 0, i32 0), [4 x i8] %15) %17 = add i32 %14, %16 %18 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @82, i32 0, i32 0)) %19 = add i32 %17, %18 %20 = add i32 %19, %4 %21 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @83, i32 0, i32 0)) %22 = add i32 %20, %21 ret void
}
; Function Attrs: noinline nounwind optnone
define dso_local void @test4() #0 {
entry:
%a = alloca %struct.T4A, align 8 %0 = bitcast %struct.T4A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %0, i8* align 8 bitcast (%struct.T4A* @test4.a to i8*), i64 8, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @84, i32 0, i32 0)) %2 = getelementptr inbounds %struct.T4A, %struct.T4A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([91 x i8], [91 x i8]* @85, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([90 x i8], [90 x i8]* @86, i32 0, i32 0)) %6 = bitcast %union.anon.0* %2 to %struct.anon* %7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([96 x i8], [96 x i8]* @87, i32 0, i32 0)) %8 = add i32 %5, %7 %9 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([91 x i8], [91 x i8]* @88, i32 0, i32 0)) %10 = getelementptr inbounds %struct.anon, %struct.anon* %6, i32 0, i32 0 %11 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @89, i32 0, i32 0)) %12 = add i32 %9, %11 %13 = load i8*, i8** %10, align 8 %14 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @90, i32 0, i32 0), i8* %13) %15 = add i32 %12, %14 %16 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @91, i32 0, i32 0)) %17 = add i32 %15, %16 %18 = add i32 %17, %8 %19 = bitcast %union.anon.0* %2 to %struct.anon.1* %20 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([96 x i8], [96 x i8]* @92, i32 0, i32 0)) %21 = add i32 %18, %20 %22 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([91 x i8], [91 x i8]* @93, i32 0, i32 0)) %23 = getelementptr inbounds %struct.anon.1, %struct.anon.1* %19, i32 0, i32 0 %24 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @94, i32 0, i32 0)) %25 = add i32 %22, %24 %26 = load i32, i32* %23, align 8 %27 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @95, i32 0, i32 0), i32 %26) %28 = add i32 %25, %27 %29 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @96, i32 0, i32 0)) %30 = add i32 %28, %29 %31 = add i32 %30, %21 %32 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @97, i32 0, i32 0)) %33 = add i32 %31, %32 %34 = add i32 %33, %4 %35 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @98, i32 0, i32 0)) %36 = add i32 %34, %35 ret void
}
attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { argmemonly nounwind }
attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"wchar_size", i32 2}
!1 = !{!"clang version 7.0.0 (trunk 329536)"}
1 warning generated.
Sorry about it, I also have the warning on my machine, but not the error you get...
Those test are actually working on my different linux machines, that's really weird.
This one is actually really weird, because I could find manually the missing pattern in your output.. I just don't get what is happening.
Ok, I found the problem. In fact the size of long is 4 bytes on your machine, but 8 bytes on mine.
This makes this // CHECK: [[LOAD1:%[0-9]+]] = load i64, i64* [[RES1]], fail.
Do you know a smart way to do it without dealing with type sizes ?
test/CodeGen/dump-struct-builtin.c | ||
---|---|---|
1 ↗ | (On Diff #141913) | This should be // RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s or something |
You should probably run the test with -triple=x86_64-unknown-linux (or whatever the triple for your host machine happens to be). Otherwise they depend on the default clang triple which could have a different size long.
You should probably run the test with -triple=x86_64-unknown-linux (or whatever the triple for your host machine happens to be). Otherwise they depend on the default clang triple which could have a different size long.
I think the issue has to do with bit-width. From unit5():
// Your test // 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( // My results ; Function Attrs: noinline nounwind optnone define dso_local void @unit5() #0 { entry: %a = alloca %struct.U5A, align 4 %0 = bitcast %struct.U5A* %a to i8* call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%struct.U5A* @unit5.a to i8*), i64 4, i1 false) %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @16, i32 0, i32 0)) %2 = getelementptr inbounds %struct.U5A, %struct.U5A* %a, i32 0, i32 0 %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @17, i32 0, i32 0)) %4 = add i32 %1, %3 %5 = load i32, i32* %2, align 4 %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @18, i32 0, i32 0), i32 %5) %7 = add i32 %4, %6 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @19, i32 0, i32 0)) %9 = add i32 %7, %8 ret void }
You are testing that the load is an i64 but in my results it's an i32. An explicit target triple on the RUN line solves the issue.
I see we all found the solution at the same time. Yay teamwork! :-D
I've committed (with the test fixed up) in r329762.
Can you look to see if we have an existing diagnostic that can cover this instead?