snsystems / llvm-prepo Goto Github PK
View Code? Open in Web Editor NEWProgram repository project has moved to https://github.com/SNSystems/llvm-project-prepo
License: Other
Program repository project has moved to https://github.com/SNSystems/llvm-project-prepo
License: Other
Compile the following LLVM IR code:
target triple = "x86_64-pc-linux-gnu-repo"
%class.btVector3 = type { [4 x float] }
$f = comdat any
define linkonce_odr void @f(%class.btVector3* %this, float* dereferenceable(4) %s) comdat align 2 !repo_ticket !0 {
entry:
%s.addr = alloca float*, align 8
%ref.tmp = alloca float, align 4
%0 = load float*, float** %s.addr, align 8
%1 = load float, float* %0, align 4
%div = fdiv float 1.000000e+00, %1
store float %div, float* %ref.tmp, align 4
ret void
}
using
$ rm clang.db
$ llc -filetype=obj %s -o %t.o
$ repo2obj %t.o -o %t.elf
$ llvm-readobj -elf-section-groups %t.elf | FileCheck %s
This produces one group section:
Groups {
Group {
Name: .group (24)
Index: 3
Type: COMDAT (0x1)
Signature: f
Section(s) in group [
.text.f (4)
.rela.text.f (5)
]
}
}
However, the section ‘.rodata.cst4.f’ should belong to the group section as well.
Compile the following code:
void t1()
{
int a = 10;
a++;
}
void t2()
{
int b = 10;
b++;
}
using
$ rm clang.db
$ clang -O0 -S -emit-llvm -gline-tables-only -target x86_64-pc-linux-gnu-repo -o test.ll test.c
The generated test.ll file is:
define void @t1() #0 !dbg !9 !repo_ticket !7 {
...
}
define void @t2() #0 !dbg !14 !repo_ticket !8 {
...
}
!7 = !TicketNode(name: "t1", digest: [16 x i8] c"1\C7x\C9\87\F2v\A7\C7)8n\1C\D2\9Cd", linkage: external, pruned: false)
!8 = !TicketNode(name: "t2", digest: [16 x i8] c"1\C7x\C9\87\F2v\A7\C7)8n\1C\D2\9Cd", linkage: external, pruned: false)
!9 = distinct !DISubprogram(name: "t1", scope: !1, file: !1, line: 1, type: !10, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, retainedNodes: !2)
!10 = !DISubroutineType(types: !2)
!11 = !DILocation(line: 3, column: 7, scope: !9)
!12 = !DILocation(line: 4, column: 4, scope: !9)
!13 = !DILocation(line: 5, column: 1, scope: !9)
!14 = distinct !DISubprogram(name: "t2", scope: !1, file: !1, line: 7, type: !10, isLocal: false, isDefinition: true, scopeLine: 8, isOptimized: false, unit: !0, retainedNodes: !2)
!15 = !DILocation(line: 10, column: 7, scope: !14)
!16 = !DILocation(line: 12, column: 4, scope: !14)
!17 = !DILocation(line: 14, column: 1, scope: !14)
The functions of “t1” and “t2” have the same digest, which is wrong. The digests should be different since the functions have the different debug line location.
A trivial source file such as:
struct foo {
foo ();
};
static foo f;
Causes the compiler to fail with as message something like:
getExplicitSectionGlobal not yet implemented
UNREACHABLE executed at .../llvm-prepo/lib/CodeGen/TargetLoweringObjectFileImpl.cpp:615!
Compile the following code:
double CalculateOptimalEdits() {
unsigned long a;
return a + 1.9;
}
using
$ rm clang.db
$ clang -O0 -c -target x86_64-pc-linux-gnu-repo -o test.o test.c
Assertion failure is given:
Assertion failed: (mm & mask) == 0 && "The same index must not appear more than once in the " "collection of sparse indices", file C:\MyWork\git\github\llvm-prepo\tools\pstore\include\pstore_mcrepo/sparse_array.hpp, line 656
The target triple should be recorded along with the compilation. This can then be used:
This bug is spinning out from bug 26.
The existing -O0, -O1, -O2 or -O3 pass pipelines affect the user project build time. We need to tune the ‘RepoTicketGenerationPass’ and ‘RepoPruningPass’ pass order to achieve optimal performance.
Whilst working on bug #23 I noticed that the repository representation of the little code snippet there wasn't using the "mergeable 1 byte C string" section for the constant ASCIIZ string whereas the ELF output did.
Compile the following code:
__thread int errno;
int get_errno() { return errno; }
using
$ rm clang.db
$ clang -O0 -c -target x86_64-pc-linux-gnu-repo -std=gnu++11 -o test.o test.cpp
Assertion failure:
TLS not implemented for this target.
Add the TLS implementation to fix this issue.
We are building and testing the pstore-broker-unit-tests using the llvm-prepo toolchain. When linking all elf object files, the following linking error is given:
/usr/bin/ld: _ZN6pstore7logging7details13log_streambufE: TLS definition in libpstore-support-lib.a(logging.cpp.o.elf) section .tbss mismatches non-TLS reference in libpstore-broker-lib.a(command.cpp.o.elf)
libpstore-support-lib.a: error adding symbols: Bad value
Compile the following code:
int a;
using
$ rm clang.db
$ clang -O0 -c -target x86_64-pc-linux-gnu-repo -o test.o test.c
Compilation failed with the following error:
fatal error: error in backend: The digest of missing repository fragment 1dfd1a0c15d34e5f22f6d37e47077cf7 was found in a ticket member.
Compile the following code:
extern thread_local int i;
int &get() { return i; }
using
$ rm clang.db
$ clang -O0 -c -target x86_64-pc-linux-gnu-repo -std=gnu++11 -o test.o test.cpp
Compilation failure:
fatal error: error in backend: Unsupported linkage type
Compile the pstore library using the built llvm-repo/clang-repo toolchain and compare the compile time beween ELF and Repo (not including the link time). The task invokes:
1. Build llvm-repo/clang-repo toolchain with Release configuration.
2. Build pstore library using built llvm-repo/clang-repo compiler targeted on ELF, get the compile
time (note: build four times and get average compile time).
3. Build pstore library using built llvm-repo/clang-repo compiler targeted on Repo, get the compile
time (note: remove clang.db before build).
4. Build pstore library again and get the compile time (note: all fragments are in the database.)
Compile the following code:
template <typename _Tp> class new_allocator {
public:
typedef _Tp *pointer;
~new_allocator() {}
};
template <typename _CharT> class basic_string {
struct _Alloc_hider : new_allocator<char> {
_Alloc_hider(pointer __dat) : _M_p(__dat) {}
pointer _M_p;
};
_Alloc_hider _M_dataplus;
public:
basic_string(_CharT *__s) : _M_dataplus(__s) {}
};
int *MakeAndRegisterTestInfo(basic_string<char> code_location);
int *test_info_ = MakeAndRegisterTestInfo("test.cpp");
using
$ rm clang.db
$ clang -O0 -c -target x86_64-pc-linux-gnu-repo -o test.o test.cpp
$ clang -O0 -c -target x86_64-pc-linux-gnu-repo -o test1.o test.cpp
The test.cpp is compiled twice with clang.
The first time: the resulting repository fragment contains a definition for a string named "L.str", the "main" fragment contains a fixup which references a string named ".L.str". It is correct.
The Second time: the resulting repository fragment contains a definition for a string named "L.str", but the "main" fragment contains a fixup which references a string named ".str". This mismatch is obviously wrong.
Compile the following code:
void t1()
{
int a = 10;
a++;
}
void t2()
{
int b = 10;
b++;
}
using
$ rm clang.db
$ clang -O0 -S -emit-llvm -fno-exceptions -target x86_64-pc-linux-gnu-repo -o repo.ll test.c
$ llc -filetype=obj -o repo.o repo.ll
$ pstore-dump –all-fragments clang.db
The list of fragments in the repository is:
fragments :
- digest : 649cd21c6e3829c7a776f287c978c731
fragment :
- type : text
contents :
align : 16
data :
- 0: pushq %rbp
- 1: movq %rsp, %rbp
- 4: movl $10, -4(%rbp)
- 11: movl -4(%rbp), %eax
- 14: addl $1, %eax
- 17: movl %eax, -4(%rbp)
- 20: popq %rbp
- 21: retq
- 22: nop
- 23: nop
- 24: nop
- 25: nop
- 26: nop
- 27: nop
- 28: nop
- 29: nop
- 30: nop
- 31: nop
- 32: pushq %rbp
- 33: movq %rsp, %rbp
- 36: movl $10, -4(%rbp)
- 43: movl -4(%rbp), %eax
- 46: addl $1, %eax
- 49: movl %eax, -4(%rbp)
- 52: popq %rbp
- 53: retq
ifixups : [ ]
xfixups : [ ]
The function t1 and t2 have been merge into a single fragment, whose data is wrong.
If you compile the program below:
extern int printf (char const *,...)[
int main () {
printf ("Hello world\n");
}
The resulting repository fragment contains a definition for a string named ".str", but the "main" fragment contains a fixup which references a string named ".L.str". This mismatch is obviously wrong.
When the source file only contains the function declaration and is built targeted on the repo, the incorrect error message is given.
Here is the source file:
extern int j(); /* j has external linkage */
LLVM ERROR: Failed to get 'repo.tickets' module metadata!
We are building and testing the pstore-support-unit-tests using the llvm-prepo toolchain by the following steps:
When linking all elf object files, the following linking error is given:
test_error.cpp.o.elf:(.init_array+0x0): undefined reference to `_GLOBAL__sub_I_gtest_all.cc'
test_file.cpp.o.elf:(.init_array+0x0): undefined reference to `_GLOBAL__sub_I_gtest_all.cc'
test_gsl.cpp.o.elf:(.init_array+0x0): undefined reference to `_GLOBAL__sub_I_gtest_all.cc'
...
There’s a basic implementation of debug-line support checked into the llvm-prepo github repository. It’s currently on a branch (“debug_line”). The task involves: clean up the code and then merge it back to the master branch.
Compile the following code:
int a; //uninitialized
int b = 0; //Zero initialized
using
$ rm clang.db
$ clang -O0 -c -target x86_64-pc-linux-gnu-repo -o test.o test.c
This is being stored in the repository as:
pstore-dump -ticket test.o clang.db
- file :
path : clang.db
size : 4194304
tickets :
- id : 5e30ae41-98a7-421e-8eee-466de7bb9e4e
ticket :
members :
ticket_member :
- digest : 9094c1bc4813b45686785e1a0e2bc1ca
name : a
linkage : external
- digest : 5cd1a968567ef37fcd2aa2ba0cae58b2
name : b
linkage : common
path : \\\\?\\C:\\MyWork\\repo_bug\\bug19
By default, 'a' is zero initialized. The digest of 'a' is wrong and should be the same as b.
A simple IR code (test.ll):
target triple = "x86_64-pc-linux-gnu"
@.str.1 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1
@.str.2 = private unnamed_addr constant [41 x i8] c"{{ SCEBenchmark_TIMETAKEN_MS : %llu }}\0A\00"
@.str.3 = private unnamed_addr constant [26 x i8] c"{{ SCEBenchmark_END }}\0A\1A\0A\00", align 1
declare i32 @printf(i8* nocapture readonly, ...)
define void @test() align 2 {
entry:
%call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0))
%call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([41 x i8], [41 x i8]* @.str.2, i32 0, i32 0))
%call4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @.str.3, i32 0, i32 0))
ret void
}
define i32 @foo() {
entry:
ret i32 1
}
Compiled to the repo with a command something like:
$ rm clang.db
$ clang -O3 -c -target x86_64-pc-linux-gnu-repo test.ll -o test.first.o
Produces ticket members in ticket file.
$ pstore-dump -all-tickets clang.db
---
- file :
path : clang.db
size : 4194304
tickets :
- digest : ca35124551f17daa8911fd4af33fbaf1
ticket :
members :
- digest : 28a6c73189942642754546213fc3c3a4
name : test
linkage : external
- digest : 9379e47d32813ce7d140c5bf233fe11f
name : foo
linkage : external
- digest : 4f8f724974d0cf544b2f61d400896a0c
name : .str.2
linkage : internal
- digest : 88dfbeb7f039a7c77d5b7ddec82cfefa
name : str
linkage : internal
path : \\\\?\\C:\\MyWork\\repo_bug\\remove-global-object
...
Modify the source file (test.ll) and change the function foo only:
...
define i32 @foo() {
entry:
ret i32 2
}
Produces a new ticket (5252b9fa7d80e491defdc255500b1171).
$ pstore-dump -all-tickets clang.db
---
- file :
path : clang.db
size : 4194304
tickets :
- digest : 5252b9fa7d80e491defdc255500b1171
ticket :
members :
- digest : 28a6c73189942642754546213fc3c3a4
name : test
linkage : external
- digest : 7dc81a03aa5d65c469c71c77ff9f345c
name : foo
linkage : external
- digest : 4f8f724974d0cf544b2f61d400896a0c
name : .str.2
linkage : internal
path : \\\\?\\C:\\MyWork\\repo_bug\\remove-global-object
- digest : ca35124551f17daa8911fd4af33fbaf1
ticket :
members :
- digest : 28a6c73189942642754546213fc3c3a4
name : test
linkage : external
...
The fragment of function 'test' (28a6c73189942642754546213fc3c3a4):
$ pstore-dump -all-fragments clang.db
---
...
fragments :
- digest : 28a6c73189942642754546213fc3c3a4
fragment :
- type : text
contents :
align : 16
data :
- 0: pushq %rax
- 1: movl $10, %edi
- 6: callq 0
- 11: movl $0, %edi
- 16: xorl %eax, %eax
- 18: callq 0
- 23: movl $0, %edi
- 28: popq %rax
- 29: jmp 0
ifixups : [ ]
xfixups :
- name : putchar
type : 2
offset : 7
addend : 18446744073709551612
- name : .str.2
type : 10
offset : 12
addend : 0
- name : printf
type : 2
offset : 19
addend : 18446744073709551612
- name : str
type : 10
offset : 24
addend : 0
- name : puts
type : 2
offset : 30
addend : 18446744073709551612
There is external relocation to symbol 'str', but 'str' is not in the ticket (5252b9fa7d80e491defdc255500b1171).
This caused a link error: undefined reference to 'str'.
Take the following little example (repo.cpp):
int bar = 1;
template <typename T>
T foo (T t) { return t + bar; }
int qaz (int t) { return foo (t); }
After compiling and running through repo2obj, we get the following sections in the ELF file:
$ clang++ -O0 -c -target x86_64-pc-linux-gnu-repo -o rela.o rela.cpp
$ repo2obj -o rela.elf.o rela.o
$ llvm-objdump -section-headers rela.elf.o
rela.elf.o: file format ELF64-x86-64
Sections:
Idx Name Size Address Type
0 00000000 0000000000000000
1 .shstrtab 0000004e 0000000000000000
2 .strtab 0000001c 0000000000000000
3 .symtab 00000060 0000000000000000
4 .group 0000000c 0000000000000000
5 .text 00000019 0000000000000000 TEXT DATA
6 .rela.text 00000018 0000000000000000
7 .text._Z3fooIiET_S0_ 00000015 0000000000000000 TEXT DATA
8 .rela.text 00000018 0000000000000000
9 .data 00000004 0000000000000000 DATA
$
Sections 6 and 8 are both named .rela.text
(6 targets .text
and 8 targets .text. _Z3fooIiET_S0_
). Although it's slightly less space-efficient, as an aid to debugging with this stuff it would be useful if section 8 was named .rela.text. _Z3fooIiET_S0_
.
As discussed in SNSystems/pstore#21, a bss section will be implemented as a special section. The repo2obj and MC object writer need to be updated correspondingly.
Compile the following code:
namespace pstore {
template <typename ProcessPathFunction, typename BufferType>
int process_file_name(ProcessPathFunction, BufferType &p2) {
p2.capacity();
}
template <typename, int = 256> class small_vector {
public:
void capacity();
};
void process_file_name() {
auto read_link = [] {};
small_vector<char> buffer;
process_file_name(read_link, buffer);
}
} // namespace pstore
using
$ rm clang.db
$ clang -O2 -c -target x86_64-pc-linux-gnu-repo -std=gnu++11 -o test.o test.cpp
Compilation failed with the following error:
fatal error: error in backend: The digest of missing repository fragment 99effd5b5772b7cf34cc3b757a620c1c was found in a ticket member.
Compile a small example such as:
double const d = 1.0;
Compile it:
$ rm clang.db
$ clang -c -O0 -target x86_64-pc-linux-gnu-repo double.c
This is being stored in the repository as:
$ pstore-dump --fragments clang.db
---
- file :
path : clang.db
size : 4194304
fragments :
- digest : be21f32fb7eefb5c5d6fb94c7e481974
fragment :
- type : ReadOnly
contents :
data : !!binary |
AAAAAAAA8D8=
ifixups : [ ]
xfixups : [ ]
...
$
The data ought to be in a section of type mergeable-const-8 rather than read-only.
Compile the following code:
template <typename _CharT>
class basic_ostream;
typedef basic_ostream<char> ostream;
template <typename _CharT>
basic_ostream<_CharT> &__ostream_insert(basic_ostream<_CharT> &__out,
_CharT *__s);
inline basic_ostream<char> &operator<<(basic_ostream<char> &__out, char *__s) {
__ostream_insert(__out, __s);
}
ostream &operator<<(ostream &stream, int version) {
char *str = "";
switch (version) {
case 1:
str = "time_based";
break;
case 2:
str;
case 3:
str = "name_based_md5";
}
return stream << str;
}
using
$ rm clang.db
$ clang++ -target x86_64-pc-linux-gnu-repo -O2 -std=gnu++11 -c test.cpp
Compilation failed with the following error:
Assertion failed: Val && "isa<> used on a null pointer", file C:\MyWork\git\github\llvm-prepo\include\llvm/Support/Casting.h, line 106
Compile the following code:
extern int printf (char const * format, ...);
int main () {
printf ("%f\n", 1.0);
}
using
$ rm clang.db
$ clang -O0 -c -target x86_64-pc-linux-gnu-repo -o double.o double.c
$ pstore-dump --fragments --tickets clang.db
This produces a fragment (947261b89ef2fd43da823ee4f676e2c9) which contains two sections:
- file :
path : clang.db
size : 4194304
fragments :
- digest : 947261b89ef2fd43da823ee4f676e2c9
fragment :
- type : Text
contents :
data : !!binary |
VUiJ5UiD7BBIvwAAAAAAAAAA8g8QBQAAAACwAegAAAAAMcmJRfyJyEiDxBBdww==
ifixups : [ ]
xfixups :
- name : .L.str
type : 1
offset : 10
addend : 0
- name : .LCPI0_0
type : 2
offset : 22
addend : 18446744073709551612
- name : printf
type : 2
offset : 29
addend : 18446744073709551612
- type : MergeableConst8
contents :
data : !!binary |
AAAAAAAA8D8=
ifixups : [ ]
xfixups : [ ]
- digest : 636a38b68cbba28666408b4cf3bc4620
fragment :
- type : ReadOnly
contents :
data : !!binary |
JWYKAA==
ifixups : [ ]
xfixups : [ ]
tickets :
- uuid : 40440bb0-4741-4e2a-913f-ad6a6b9c89a8
ticket :
members :
ticket_member :
- digest : 636a38b68cbba28666408b4cf3bc4620
name : .L.str
linkage : internal
- digest : 947261b89ef2fd43da823ee4f676e2c9
name : main
linkage : external
path : ...
...
The ticket associated with this compilation does not contain a definition of the .LCPI0_0
symbol which is referenced from one of the main
fragment's text-section external fixups. This should really be an internal fixup referring to the MergeableConst8 section.
This task is spinning out from issue #45. It invokes:
Compile the following code:
class vector {
public:
double & operator[] (unsigned __n){}
};
void CalculateOptimalEdits () {
vector costs;
costs[0] = 1;
}
with:
.../Debug/bin/clang++ -w -g -std=c++11 -c out4.c -target x86_64-pc-linux-gnu-repo
Compile the following code:
template <typename _CharT>
class basic_ostream;
typedef basic_ostream<char> ostream;
template <typename _CharT>
basic_ostream<_CharT> &__ostream_insert(basic_ostream<_CharT> &__out,
_CharT *__s);
inline basic_ostream<char> &operator<<(basic_ostream<char> &__out, char *__s) {
__ostream_insert(__out, __s);
}
ostream &operator<<(ostream &stream, int version) {
char *str = "";
switch (version) {
case 1:
str = "time_based";
break;
case 2:
str;
case 3:
str = "name_based_md5";
}
return stream << str;
}
using
$ rm clang.db
$ clang++ -target x86_64-pc-linux-gnu-repo -O2 -std=gnu++11 -c test.cpp
$ clang++ -target x86_64-pc-linux-gnu-repo -O2 -std=gnu++11 -c test.cpp
The list of generations in the repository is:
- file :
path : clang.db
size : 4194304
log :
- { number: 2, size: 208, time: 2018-03-01T09:36:37Z }
- { number: 1, size: 1176, time: 2018-03-01T09:36:36Z }
- { number: 0, size: 0, time: 2018-03-01T09:36:36Z }
...
During the second time build, there is no database transaction since the source file keeps the same. The latest revision number should be 1 instead of 2.
At the moment, the repo2obj tool gathers all of the .group sections together at the front of the section-header table. This was a simple way of satisfying ELF's constraint that GROUP sections must appear before the sections that they reference.
In contrast, the compiler's ELF emission code places a GROUP section immediately prior to the sections that it references. This makes the typical output order something ".group"/".text.foo"/".rela.text.foo".
To make problem diagnosis easier, I'd like to arrange for the repo2obj files to match the compiler's files as closely as possible so that any important differences can be spotted easily.
Test the llvm-prepo toolchain using the pstore unit tests. The task invokes:
1. Build llvm-repo/clang-repo toolchain with Debug configuration.
2. Compile the pstore unit tests targeted on Repo using the built llvm-repo/clang-repo compiler.
3. Convert the Repo object files to the ELF object files by using repo2obj.
4. Link the ELF object files to generate an executable ELF file.
5. Run the generated executable file and expect to pass the unit tests.
6. Repeat the steps 2 to 5 (note: all fragments are in the database.)
The repository uses a ticket file to represent the results of a particular compilation. At the moment a UUID is used as the key to the ticket index. This is simple to implement but means that a recompilation will always result in data being recorded in the data store (since a UUID is by definition unique).
This now seems a little silly, so compute a hash of the ticket contents and use this as the key to the ticket index.
This bug is spinning out from bug 32.
Compile the following code:
target datalayout = "e-m:r-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-repo"
%struct._xmlParserCtxt = type opaque
%struct._xmlHashTable = type opaque
%struct._xmlEntity = type opaque
define void @htmlFreeParserCtxt(%struct._xmlParserCtxt* %ctxt) {
entry:
%ctxt.addr = alloca %struct._xmlParserCtxt*, align 8
store %struct._xmlParserCtxt* %ctxt, %struct._xmlParserCtxt** %ctxt.addr, align 8
%0 = load %struct._xmlParserCtxt*, %struct._xmlParserCtxt** %ctxt.addr, align 8
call void @xmlFreeParserCtxt(%struct._xmlParserCtxt* %0)
ret void
}
declare void @xmlFreeParserCtxt(%struct._xmlParserCtxt*)
define void @xmlFreeEntitiesTable(%struct._xmlHashTable* %table) {
entry:
%table.addr = alloca %struct._xmlHashTable*, align 8
store %struct._xmlHashTable* %table, %struct._xmlHashTable** %table.addr, align 8
%0 = load %struct._xmlHashTable*, %struct._xmlHashTable** %table.addr, align 8
call void @xmlHashFree(%struct._xmlHashTable* %0, void (i8*, i8*)* bitcast (void (%struct._xmlEntity*, i8*)* @xmlFreeEntityWrapper to void (i8*, i8*)*))
ret void
}
declare void @xmlHashFree(%struct._xmlHashTable*, void (i8*, i8*)*)
declare void @xmlFreeEntityWrapper(%struct._xmlEntity* %entity, i8* %name)
using
$ rm clang.db
$ opt test.ll -S -o test.opt.ll
The generated optimised test.opt.ll file is:
define void @htmlFreeParserCtxt(%struct._xmlParserCtxt* %ctxt) !repo_ticket !0 {
...
}
define void @xmlFreeEntitiesTable(%struct._xmlHashTable* %table) !repo_ticket !1 {
...
}
!0 = !TicketNode(name: "htmlFreeParserCtxt", digest: [16 x i8] c"\CF\B3\F7h\E8\F9\E7\0C~&\92\F0\1AG\A2\E5", linkage: external, pruned: false)
!1 = !TicketNode(name: "xmlFreeEntitiesTable", digest: [16 x i8] c"\CF\B3\F7h\E8\F9\E7\0C~&\92\F0\1AG\A2\E5", linkage: external, pruned: false)
The functions of “htmlFreeParserCtxt” and “xmlFreeEntitiesTable” have the same digest, which is wrong. The digests should be different.
$ cat 1.cpp
typedef char a __attribute__((__vector_size__(8)));
void b() { __builtin_ia32_palignr((a)0L, (a)0L, 0); }
$ ./clang++ -c 1.cpp -march=btver2 -target x86_64-pc-gnu-linux
$ ./clang++ -c 1.cpp -march=btver2 -target x86_64-pc-gnu-linux-repo
Unknown type!
UNREACHABLE executed at /mnt/e/work/prepo/llvm/lib/IR/RepoHashCalculator.cpp:131!
#0 0x00007f14fc63d6aa llvm::sys::PrintStackTrace(llvm::raw_ostream&) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x243d6aa)
#1 0x00007f14fc63b2d6 llvm::sys::RunSignalHandlers() (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x243b2d6)
#2 0x00007f14fc63b675 SignalHandler(int) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x243b675)
#3 0x00007f14f9bf2890 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x12890)
#4 0x00007f14f887ee97 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x3ee97)
#5 0x00007f14f8880801 abort (/lib/x86_64-linux-gnu/libc.so.6+0x40801)
#6 0x00007f14fc5dc6ba (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x23dc6ba)
#7 0x00007f14fc170e87 llvm::HashCalculator::hashType(llvm::Type*) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x1f70e87)
#8 0x00007f14fc173b44 llvm::FunctionHashCalculator::hashInstruction(llvm::Instruction const*) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x1f73b44)
#9 0x00007f14fc1741a9 llvm::FunctionHashCalculator::hashBasicBlock(llvm::BasicBlock const*) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x1f741a9)
#10 0x00007f14fc174304 llvm::FunctionHashCalculator::hashFunction() (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x1f74304)
#11 0x00007f14fc174732 llvm::FunctionHashCalculator::calculateHash() (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x1f74732)
#12 0x00007f14fc139e72 llvm::DenseMapIterator<llvm::GlobalObject const*, llvm::ticketmd::GOInfo, llvm::DenseMapInfo<llvm::GlobalObject const*>, llvm::detail::DenseMapPair<llvm::GlobalObject const*, llvm::ticketmd::GOInfo>, true> llvm::ticketmd::calculateInitialDigestAndDependencies<llvm::Function>(llvm::Function const*, llvm::DenseMap<llvm::GlobalObject const*, llvm::ticketmd::GOInfo, llvm::DenseMapInfo<llvm::GlobalObject const*>, llvm::detail::DenseMapPair<llvm::GlobalObject const*, llvm::ticketmd::GOInfo> >&) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x1f39e72)
#13 0x00007f14fc13a7e4 llvm::ticketmd::updateInitialDigestAndGetDependencies(llvm::GlobalObject const*, llvm::MD5&, llvm::DenseMap<llvm::GlobalObject const*, llvm::ticketmd::GOInfo, llvm::DenseMapInfo<llvm::GlobalObject const*>, llvm::detail::DenseMapPair<llvm::GlobalObject const*, llvm::ticketmd::GOInfo> >&, llvm::ticketmd::GONumber&) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x1f3a7e4)
#14 0x00007f14fc13b67c void llvm::ticketmd::updateDigestUseCallDependencies<llvm::ticketmd::generateTicketMDs(llvm::Module&)::{lambda(llvm::GlobalObject const*, llvm::MD5&, llvm::DenseMap<llvm::GlobalObject const*, llvm::ticketmd::GOInfo, llvm::DenseMapInfo<llvm::GlobalObject const*>, llvm::detail::DenseMapPair<llvm::GlobalObject const*, llvm::ticketmd::GOInfo> >&)#1}>(llvm::GlobalObject const*, llvm::MD5&, llvm::DenseMap<llvm::GlobalObject const*, unsigned int, llvm::DenseMapInfo<llvm::GlobalObject const*>, llvm::detail::DenseMapPair<llvm::GlobalObject const*, unsigned int> >&, llvm::DenseMap<llvm::GlobalObject const*, llvm::ticketmd::GOInfo, llvm::DenseMapInfo<llvm::GlobalObject const*>, llvm::detail::DenseMapPair<llvm::GlobalObject const*, llvm::ticketmd::GOInfo> >&, llvm::ticketmd::generateTicketMDs(llvm::Module&)::{lambda(llvm::GlobalObject const*, llvm::MD5&, llvm::DenseMap<llvm::GlobalObject const*, llvm::ticketmd::GOInfo, llvm::DenseMapInfo<llvm::GlobalObject const*>, llvm::detail::DenseMapPair<llvm::GlobalObject const*, llvm::ticketmd::GOInfo> >&)#1}) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x1f3b67c)
#15 0x00007f14fc13bf05 llvm::ticketmd::generateTicketMDs(llvm::Module&) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x1f3bf05)
#16 0x00007f14fc1e8481 (anonymous namespace)::RepoTicketGeneration::runOnModule(llvm::Module&) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x1fe8481)
#17 0x00007f14fc0f79a1 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x1ef79a1)
#18 0x00007f14fc80dc24 clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::HeaderSearchOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::DataLayout const&, llvm::Module*, clang::BackendAction, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream> >) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x260dc24)
#19 0x00007f14fcf69b48 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x2d69b48)
#20 0x00007f14fd38214a clang::ParseAST(clang::Sema&, bool, bool) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x318214a)
#21 0x00007f14fcf665f8 clang::CodeGenAction::ExecuteAction() (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x2d665f8)
#22 0x00007f14fcbef7a6 clang::FrontendAction::Execute() (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x29ef7a6)
#23 0x00007f14fcbb88ce clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x29b88ce)
#24 0x00007f14fcc8b72a clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0x2a8b72a)
#25 0x00007f14faeafff8 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0xcafff8)
#26 0x00007f14fae380dc main (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0xc380dc)
#27 0x00007f14f8861b97 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b97)
#28 0x00007f14faeac24a _start (/mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0+0xcac24a)
Stack dump:
0. Program arguments: /mnt/e/work/prepo/build-gcc-native-ninja/bin/clang-6.0 -cc1 -triple x86_64-pc-linux-gnu-repo -emit-obj -mrelax-all -disable-free -main-file-name 1.cpp -mrelocation-model static -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -munwind-tables -fuse-init-array -target-cpu btver2 -dwarf-column-info -debugger-tuning=gdb -coverage-notes-file /mnt/e/work/prepo/build-gcc-native-ninja/bin/1.gcno -resource-dir /mnt/e/work/prepo/build-gcc-native-ninja/lib/clang/6.0.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/backward -internal-isystem /usr/local/include -internal-isystem /mnt/e/work/prepo/build-gcc-native-ninja/lib/clang/6.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdeprecated-macro -fdebug-compilation-dir /mnt/e/work/prepo/build-gcc-native-ninja/bin -ferror-limit 19 -fmessage-length 237 -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -o 1.o -x c++ 1.cpp
1. <eof> parser at end of file
2. Per-module optimization passes
3. Running pass 'RepoTicketGenerationPass' on module '1.cpp'.
clang-6.0: error: unable to execute command: Aborted (core dumped)
clang-6.0: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 6.0.0 (https://github.com/SNSystems/clang-prepo.git 85663ce2d0e357504b3b92e3cdf53b39056d1f7e) (https://github.com/SNSystems/llvm-prepo.git 1bfded74475ead9e577569905e185799c998863f)
Target: x86_64-pc-linux-gnu-repo
Thread model: posix
InstalledDir: /mnt/e/work/prepo/build-gcc-native-ninja/bin/.
clang-6.0: note: diagnostic msg: PLEASE submit a bug report to http://llvm.org/bugs/ and include the crash backtrace, preprocessed source, and associated run script.
clang-6.0: note: diagnostic msg:
********************
Compile the following code (test.ll):
target triple = "x86_64-pc-linux-gnu-repo"
@llvm.global_ctors = appending global [1 x { i32, void ()* }] [ { i32, void ()* } { i32 65535, void ()* @__mf_init } ]
@llvm.global_dtors = appending global [1 x { i32, void ()* }] [ { i32, void ()* } { i32 65535, void ()* @__mf_fini } ]
define void @__mf_init() {
entry:
ret void
}
define void @__mf_fini() {
entry:
ret void
}
using
$ rm clang.db
$ clang test.ll -target x86_64-pc-linux-gnu-repo -c -o repo.o
$ clang test.ll -target x86_64-pc-linux-gnu-repo -c -o repo.o
The test.ll is compiled with clang twice.
The first time success and second time failed with following error:
invalid linkage for intrinsic global variable
[1 x { i32, void ()* }]* @llvm.global_ctors
invalid linkage for intrinsic global variable
[1 x { i32, void ()* }]* @llvm.global_dtors
fatal error: error in backend: Broken module found, compilation aborted!
Compile the following code:
double test() {
return 1.9;
}
using
$ rm clang.db
$ clang -O0 -c -target x86_64-pc-linux-gnu-repo -o test.o test.cpp
$ pstore-dump --fragments clang.db
This produces a fragment (8861d2b57f667812d77e50c2bd0a8cb1) which contains two sections (Text and MergeableConst8):
---
- file :
path : clang.db
size : 4194304
fragments :
- digest : 8861d2b57f667812d77e50c2bd0a8cb1
fragment :
- type : Text
contents :
align : 65536
data : !!binary |
VUiJ5fIPEAUAAAAAXcM=
ifixups :
- section : MergeableConst8
type : 2
offset : 8
addend : 18446744073709551612
xfixups : [ ]
- type : MergeableConst8
contents :
align : 256
data : !!binary |
ZmZmZmZm/j8=
ifixups : [ ]
xfixups : [ ]
...
The section alignment is wrong. The section alignment of the Repo file is different from the ELF Section alignment. The section alignment of the ELF file should be a positive, integral power of 2 (align). However, the Repo section alignment should be stored as “log2(align) + 1”.
Compile the following code:
@x = global i32 0, align 4
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_global-ctor.ll, i8* null }]
define internal void @__cxx_global_var_init() section ".text.startup" {
entry:
%call = call i32 @_Z1fv()
store i32 %call, i32* @x, align 4
ret void
}
declare i32 @_Z1fv()
define internal void @_GLOBAL__sub_I_global-ctor.ll() section ".text.startup" {
entry:
call void @__cxx_global_var_init()
ret void
}
using
$ rm clang.db
$ opt -mtriple x86_64-pcplinux-repo -S -O3 global-ctor.ll -o first.ll
$ llc -filetype=obj first.ll
Modify the initial value of global variable x from 0 to 8:
@x = global i32 8, align 4
...
Compile the code again using:
$ opt -mtriple x86_64-pcplinux-repo -S -O3 global-ctor.ll -o second.ll
The first.ll IR code:
source_filename = "global-ctor.ll"
target triple = "x86_64-pcplinux--repo"
@x = local_unnamed_addr global i32 0, align 4, !repo_ticket !0
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_global-ctor.ll, i8* null }], !repo_ticket !1
declare i32 @_Z1fv() local_unnamed_addr
define internal void @_GLOBAL__sub_I_global-ctor.ll() section ".text.startup" !repo_ticket !3 {
entry:
%call.i = tail call i32 @_Z1fv()
store i32 %call.i, i32* @x, align 4
ret void
}
!repo.tickets = !{!2, !3, !0, !1}
!0 = !TicketNode(name: "x", digest: [16 x i8] c"U]\B8\E2'\DF\DC\15\9D\84\D0\1FY\07\C2\19", linkage: external, pruned: false)
!1 = !TicketNode(name: "llvm.global_ctors", digest: [16 x i8] c"^\08\8Eo\DD\DB\A3\CA\01\16\FE\86\C3q\A2N", linkage: appending, pruned: false)
!2 = !TicketNode(name: "__cxx_global_var_init", digest: [16 x i8] c"[\16\E1\B1\E9\919\A9\8Et\82\A5Nh\D9\F8", linkage: internal, pruned: false)
!3 = !TicketNode(name: "_GLOBAL__sub_I_global-ctor.ll", digest: [16 x i8] c"\13\B0 \CAc?_\E9\17\99W=O\0Dv#", linkage: internal, pruned: false)
The second.ll IR code:
source_filename = "global-ctor.ll"
target triple = "x86_64-pcplinux--repo"
@x = local_unnamed_addr global i32 8, align 4, !repo_ticket !0
!repo.tickets = !{!1, !2, !0, !3}
!0 = !TicketNode(name: "x", digest: [16 x i8] c"\E2\CB=\E1\FET\F5>e6\AE\B3\16\88\0D=", linkage: external, pruned: false)
!1 = !TicketNode(name: "__cxx_global_var_init", digest: [16 x i8] c"\E4\A0\F0\9D\01\E9\D8\A8(`P\C26\C9\D4\ED", linkage: internal, pruned: false)
!2 = !TicketNode(name: "_GLOBAL__sub_I_global-ctor.ll", digest: [16 x i8] c"0\0C\F6\F4\84,\14q>~4%cy\93\FB", linkage: internal, pruned: false)
!3 = !TicketNode(name: "llvm.global_ctors", digest: [16 x i8] c"^\08\8Eo\DD\DB\A3\CA\01\16\FE\86\C3q\A2N", linkage: appending, pruned: true)
The digest value of llvm.global_ctors is wrong and should be different between two time compilations since the initial value of global variable 'x' is changed.
We are building and testing the pstore-support-unit-tests using the llvm-prepo toolchain by the following steps:
When linking all elf object files, the following linking error is given:
test_file.cpp.o.elf:(.init_array+0x0): multiple definition of `llvm.global_ctors'
test_error.cpp.o.elf:(.init_array+0x0): first defined here
test_gsl.cpp.o.elf:(.init_array+0x0): multiple definition of `llvm.global_ctors'
test_error.cpp.o.elf:(.init_array+0x0): first defined here
test_small_vector.cpp.o.elf:(.init_array+0x0): multiple definition of `llvm.global_ctors'
test_error.cpp.o.elf:(.init_array+0x0): first defined here
test_utf.cpp.o.elf:(.init_array+0x0): multiple definition of `llvm.global_ctors'
test_error.cpp.o.elf:(.init_array+0x0): first defined here
libgmock_main.a(gmock-all.cc.o.elf):(.init_array+0x0): multiple definition of `llvm.global_ctors'
test_error.cpp.o.elf:(.init_array+0x0): first defined here
libgmock_main.a(gmock_main.cc.o.elf):(.init_array+0x0): multiple definition of `llvm.global_ctors'
test_error.cpp.o.elf:(.init_array+0x0): first defined here
libgmock_main.a(gtest-all.cc.o.elf):(.init_array+0x0): multiple definition of `llvm.global_ctors'
test_error.cpp.o.elf:(.init_array+0x0): first defined here
This bug is spinning out from bug 26.
During the second time build (targeted on Repo), there shouldn’t be any database transaction happen since all source files keep the same. However, a new file ticket has been insert to the database when compiling the pstore_mcrepo/fragment.cpp again.
This task invokes:
Compile a small example (double.c) such as:
double const d = 1.0;
Compile it:
$ rm clang.db
$ clang -c -O0 -target x86_64-pc-linux-gnu-repo double.c -o double.o
This is being stored in the repository as:
$ pstore-dump --tickets clang.db
---
- file :
path : clang.db
size : 4194304
tickets :
- uuid : a4d24b49-c3d3-433f-835c-771b067c8483
ticket :
members :
ticket_member :
- digest : be21f32fb7eefb5c5d6fb94c7e481974
name : d
linkage : external
path : \\\\?\\C:\\test\\double-78171c5e.o.tmp
$
...
The ticket path should be \\?\C:\MyWork\test\double.o instead of \\?\test\double-78171c5e.o.tmp.
The RepoPruning pass removes unchanged GOs whose definitions already have binary representations in the repository. If a GO is pruned, it is currently changed from a definition to a declaration to avoid the later phases of the compiling process. However, this method will prevent inlining and other optimizations to take place.
Globals with “available_externally” linkage are never emitted into the object file corresponding to the LLVM module. They exist to allow code optimizations to take place given knowledge of the definition of the global.
The ‘available_externally’ linkage could be used in the RepoPruning pass to avoid the issue.
A simple switch statement such as:
int foo (int mode) {
switch (mode) {
case 1: return 5;
case 2: return 6;
case 3: return 7;
case 4: return 8;
default: return 9;
}
}
Compiled to the repo with a command something like:
clang -O0 -c -target x86_64-pc-linux-gnu-repo -o switch.o switch.c
Produces ifixup records in foo’s fragment which to do not have the correct addend value:
$ dumpfragment switch.o foo
---
- file :
path : ./clang.db
size : 4194304
fragments :
- digest : c2db93450e69f48bc49f046cccaf6548
fragment :
- type : text
contents :
align : 16
data : <snip instructions>
ifixups :
- { section: read_only, type: 11, offset: 39, addend: 0 }
xfixups : [ ]
- type : read_only
contents :
align : 8
data : <snip 32 zero bytes>
ifixups :
- { section: text, type: 1, offset: 0, addend: 0 }
- { section: text, type: 1, offset: 8, addend: 0 }
- { section: text, type: 1, offset: 16, addend: 0 }
- { section: text, type: 1, offset: 24, addend: 0 }
xfixups : [ ]
...
These lines are: the interesting ones: "- { section: text, type: 1, offset: 0, addend: 0}".
This contrasts with the same file compiled directly to ELF:
$ llvm-readobj --relocations switch.elf
File: switch.elf
Format: ELF64-x86-64
Arch: x86_64
AddressSize: 64bit
LoadName:
Relocations [
Section (3) .rela.text {
0x27 R_X86_64_32S .rodata 0x0
}
Section (5) .rela.rodata {
0x0 R_X86_64_64 .text 0x2D
0x8 R_X86_64_64 .text 0x39
0x10 R_X86_64_64 .text 0x45
0x18 R_X86_64_64 .text 0x51
}
Section (9) .rela.eh_frame {
0x20 R_X86_64_PC32 .text 0x0
}
]
Compile the following code:
target triple = "x86_64-pc-linux-gnu-repo"
define available_externally i32 @foo() {
ret i32 1
}
define void @bar() {
%call = call i32 @foo()
ret void
}
using
$ rm clang.db
$ opt -mtriple x86_64-pcplinux-repo -S -O3 test.ll -o first.ll
$ llc -filetype=obj first.ll
Modify the function ‘foo’ return value from 1 to 2:
define available_externally i32 @foo() {
ret i32 2
}
...
Compile the code again using:
$ opt -mtriple x86_64-pcplinux-repo -S -O3 test.ll -o second.ll
The first.ll IR code:
…
define void @bar() local_unnamed_addr #0 !repo_ticket !0 {
ret void
}
!repo.tickets = !{!0}
!0 = !TicketNode(name: "bar", digest: [16 x i8] c"\A4\ADB\9B\02\D8\EB\96\FD\A0\1A>\82\09\82#", linkage: external, pruned: false)
The second.ll IR code:
!repo.tickets = !{!0}
!0 = !TicketNode(name: " bar ", digest: [16 x i8] c"\A4\ADB\9B\02\D8\EB\96\FD\A0\1A>\82\09\82#", linkage: external, pruned: true)
The digest values of function ‘bar’ is wrong and should be different between two time compilations since its return value is changed.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.