GCCBuiltins ESECFSE19 Preprint

Download as pdf or txt
Download as pdf or txt
You are on page 1of 12

Understanding GCC Builtins to Develop Better Tools

Manuel Rigger Stefan Marr


Johannes Kepler University Linz University of Kent
Austria United Kingdom
manuel.rigger@jku.at s.marr@kent.ac.uk

Bram Adams Hanspeter Mössenböck


Polytechnique Montréal Johannes Kepler University Linz
Canada Austria
bram.adams@polymtl.ca hanspeter.moessenboeck@jku.at

ABSTRACT 2019, Tallinn, Estonia. ACM, New York, NY, USA, 12 pages. https://doi.org/
C programs can use compiler builtins to provide functionality that 10.1145/3338906.3338907
the C language lacks. On Linux, GCC provides several thousands
of builtins that are also supported by other mature compilers, such 1 INTRODUCTION
as Clang and ICC. Maintainers of other tools lack guidance on
Most C programs consist not only of C code, but also of other
whether and which builtins should be implemented to support pop-
elements, such as preprocessor directives, freestanding assembly
ular projects. To assist tool developers who want to support GCC
code files, inline assembly, compiler pragmas, and compiler builtins.
builtins, we analyzed builtin use in 4,913 C projects from GitHub.
While recent studies have highlighted the role of linker scripts [20]
We found that 37% of these projects relied on at least one builtin.
and inline assembly [53], compiler builtins have so far attracted
Supporting an increasing proportion of projects requires support
little attention. Builtins resemble functions or macros; however,
of an exponentially increasing number of builtins; however, imple-
they are not provided by libc, but are directly implemented in the
menting only 10 builtins already covers over 30% of the projects.
compiler. The following code fragment shows the usage of a GCC
Since we found that many builtins in our corpus remained unused,
builtin that returns the number of leading zeros in an integer’s
the effort needed to support 90% of the projects is moderate, re-
binary representation:
quiring about 110 builtins to be implemented. For each project,
we analyzed the evolution of builtin use over time and found that int leading_zeroes = __builtin_clz ( INT_MAX ) ; // returns 1
the majority of projects mostly added builtins. This suggests that
builtins are not a legacy feature and must be supported in future On Linux, we observed that GCC builtins are widely used and are
tools. Systematic testing of builtin support in existing tools revealed also supported by other mature compilers, such as Clang [6] and
that many lacked support for builtins either partially or completely; ICC [42]. For developers working on tools that process C code,
we also discovered incorrect implementations in various tools, in- such as compilers as well as static and dynamic analysis tools,
cluding the formally verified CompCert compiler. implementation and maintenance of GCC builtins is a large effort,
as we identified a total number of 12,339 GCC builtins, all of which
CCS CONCEPTS are potentially used by projects and thus need to be supported.
Hence, to assist developers of tools that process C code, the goal of
· Software and its engineering → Language features; Com-
this study was to investigate the use of builtins and how current
pilers.
tools support them. To this end, we analyzed the builtin use of 4,913
projects from GitHub and implemented a builtin test suite, which
KEYWORDS we used to test popular tools employed by C developers.
GCC builtins, compiler intrinsics, C GitHub projects By combining quantitative and qualitative analyses, we answer
ACM Reference Format: the following research questions (RQs):
Manuel Rigger, Stefan Marr, Bram Adams, and Hanspeter Mössenböck. 2019. RQ1: How frequently do projects use builtins? Knowing the preva-
Understanding GCC Builtins to Develop Better Tools. In Proceedings of the lence of builtins helps tool writers to judge the importance of imple-
27th ACM Joint European Software Engineering Conference and Symposium menting support for them. We hypothesized that builtins are used
on the Foundations of Software Engineering (ESEC/FSE ’19), August 26ś30, by many projects, and that any program that processes C code will
therefore encounter them, yetÐsimilar to inline assembly [53]Ðwe
Permission to make digital or hard copies of all or part of this work for personal or
classroom use is granted without fee provided that copies are not made or distributed expected that they are used in only a few source-code locations.
for profit or commercial advantage and that copies bear this notice and the full citation RQ2: For what purposes are builtins used? Knowing the primary
on the first page. Copyrights for components of this work owned by others than the use cases for builtins helps tool developers to judge whether their
author(s) must be honored. Abstracting with credit is permitted. To copy otherwise, or
republish, to post on servers or to redistribute to lists, requires prior specific permission tools can support them. For example, static analysis tools might
and/or a fee. Request permissions from permissions@acm.org. lack support for multithreading and hence be unable to deal with
ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia atomic builtins used for synchronization.
© 2019 Copyright held by the owner/author(s). Publication rights licensed to ACM.
ACM ISBN 978-1-4503-5572-8/19/08. . . $15.00 RQ3: How many builtins must be implemented to support most
https://doi.org/10.1145/3338906.3338907 projects? Tool authors who have decided to support GCC builtins

74
ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia Manuel Rigger, Stefan Marr, Bram Adams, and Hanspeter Mössenböck

would find it helpful to know the implementation order that would Selecting the projects. We analyzed projects from the popular
maximize the number of projects supported. GitHub code-hosting service. Similar to other large empirical stud-
RQ4: How does builtin usage develop over time? Understanding the ies [5, 44, 64], we selected projects based on popularity, specifically
usage of builtins over time could tell us whether projects continue the number of GitHub stars [2]. To obtain about 5,000 projects,
to add builtins or remove them. If builtins were a legacy feature we downloaded projects down to 80 stars. This cutoff point was
of compilers that projects sought to remove, the incentive of tool sufficiently large to prevent the inclusion of personal projects, home-
developers to implement them would be low. work assignments, and forks [19]. In total, we downloaded 4,998
RQ5: How well do tools support builtins? To determine the room for GitHub projects that contained in total 1,124 million lines of C
improvement in tools, we examined how well existing tools support code. This strategy allowed us to obtain a diverse set of projects
builtins. Our assumption was that state-of-the-art compilers such (see Table 1). To provide further evidence for the diversity of the
as GCC, Clang, and ICC provide full support, while other tools projects, we computed Nagappan et al.’s coverage score [35]. For
provide partial or no support. this, we used the manually validated GitHub project metadata of
We found the following: Munaiah et al.’s RepoReapers data set [33], which contained 2,329
• 12,339 GCC builtins exist, but only 3,083 were used in our of our studied projects. This subset alone obtained a coverage score
corpus of projects; of 0.966 with respect to the universe of 145,355 C projects in the
• 37% of the projects used builtins. RepoReapers data set. This indicates that our project sample is both
• Projects primarily used architecture-independent builtins, representative and diverse.
for example, to interact with the compiler, for bit-level oper-
ations, and for atomic operations. However, when a project Table 1: Overview of the projects obtained (after filtering);
would use an architecture-specific builtin, it would often be the first commit in 1984 stems from a project that was con-
used many times in the same project. verted from another version-control system.
• While mature compilers seem to provide full support for Metric Minimum Maximum Average Median
builtins, most other tools lack some builtins or have some C LOC 100 37M 228k 10k
implemented incorrectly. Notably, we found two incorrectly # commits 1 668k 4872 1147
# committers 1 17k 120 54
implemented GCC builtins in an unverified part of the for- first commit 1984-02-21 2017-11-06 - 2011-04-12
mally verified CompCert compiler. last commit 2003-12-08 2017-11-24 - 2017-11-07
• The effort of supporting a specific number of projects rises
exponentially; for example, to support half of the projects
only 32 builtins are needed. Supporting 99% of the projects, Filtering the projects. From the downloaded projects, we se-
however, requires about 1,600 builtins. lected 4,913 by filtering out those that did not meet our needs. First,
• Over time, most of the projects increasingly used builtins; we filtered out all projects that had fewer than 100 LOC, as we
nevertheless, a number of projects removed builtin uses to considered them too small to constitute C projects. GCC, forks of
reduce maintenance effort. GCC1 , and other C/C++ compilers (such as ROSE [45]) implement
Our results are expected to help tool developers in prioritizing the GCC builtins themselves, use them internally, and exercise
implementation effort, maintenance, and optimization of builtins. them in their test suites. Hence, to avoid a high number of false
Thus, this study facilitates the development of compilers such as positives, we excluded these projects; they were easy to identify, as
GCC, Clang [24], ICC, and the formally verified CompCert com- they contained the largest numbers of unique builtins.
piler [25, 26]; of static-analysis tools such as the Clang Static Ana- Identifying the builtins. Next, we identified the names of the
lyzer [66], splint [14, 15], Frama-C [65], and uno [17]; of semantic available GCC builtins, to then perform a textual search on the
models for C [23, 31]; and of alternative execution environments GitHub projects. Identifying the list of names was difficult, since
and bug-finding tools such as KLEE [3], Sulong [52, 56], the LLVM GCC builtins are not described or specified in a coherent manner,
sanitizers [58, 59], and SoftBound [36, 37]. For reproducibility and as they were added over a period of more than 30 years. Thus,
verifiability, we provide the database with GCC builtin usage, test we investigated both (I) builtins listed in the GCC documentation
suite, tools used for the analysis, and a record of the manual deci- as well as (II) builtins internal to GCC, which we automatically
sions on https:// github.com/ jku-ssw/ gcc-builtin-study. extracted from GCC’s source code (including test cases for builtins).
(I) Builtins from the documentation. Initially, we considered
only builtins described by the GCC documentation. The GCC docu-
2 METHODOLOGY mentation stated that some builtins are internal, which we initially
To answer our research questions, we analyzed builtin use in a did not want to include as we expected that other projects would not
large number of C projects and populated a SQLite3 database with use them. While extracting the names of architecture-independent
the extracted data. As detailed below, we downloaded and filtered builtins worked well, GCC also provides builtins that are specific to
projects from GitHub on which we performed a textual search for an architecture. For example, __builtin_ia32_paddq allows the
the names of the GCC builtins. To identify the builtin names, we use of x86’s paddq instruction. In some cases, architecture-specific
extracted them from the official documentation and from the GCC builtins were not described by the documentation, but referred to
source code. To exclude false-positive identifications of builtin use, 1 The projects filtered out included the GCC fork for the Xtensa processor (https:
we applied heuristics such as excluding builtin names inside string //github.com/jcmvbkbc/gcc-xtensa), and a fork that is based on GCC to dump an XML
literals and comments. description of C++ code (https://github.com/gccxml/gccxml).

75
Understanding GCC Builtins to Develop Better Tools ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia

vendor documentation, for example, the ARM C Language Exten- to a builtin name often resulted in false positives. In total, these
sions. For these builtins, the documentation of GCC version 4.8 con- measures reduced the number of records to 319k (48% of the original
tained a list of builtins, which we used instead. However, for certain number).
special-purpose architectures, obtaining such a list was impractical,
for example, for the TILE-Gx and TILEPro processor builtins. As 3 RESULTS
we expected little influence on the resultsÐoverall, architecture-
specific builtins were used infrequently (see Section 3.2)Ðwe omit- 3.1 RQ1: How frequently are builtins used?
ted analyzing these special-purpose builtins. In total, this process To answer RQ1, we considered both duplicate and unique builtin
yielded 6,040 builtins, of which 560 were architecture-independent uses per project. Counting usesÐeven if they were duplicated within
and 5,480 were architecture-specific. a projectÐallowed us to measure the overall prevalence of builtin
(II) Builtins from the GCC source code To verify that we did use. Counting project-unique uses better reflected the implementa-
not omit any commonly used builtins, we searched the projects tion effort needed to support a project, because duplicates do not
for strings starting with __builtin_. Since we found that many increase the implementation effort.
analyzed projects relied on a small number of GCC’s internal (i.e., Overall use. In total, 1,842 of the projects (37% of all projects)
undocumented) builtins (see below), we assumed that tool devel- used a common subset of 3,083 builtins. The frequency of com-
opers would also need to support these builtins. Hence, we added piler builtins varied strongly, depending on the project, and ranged
them to our search terms by including all additional __builtin_ from one builtin every 7 LOC to one every 1,680,582 LOC. The
functions that we found in the GCC source code and test suite (6,299 median frequency of builtins was one every 5,741 LOC (on average
additional builtins). In a number of cases, GCC implemented public one builtin every 20417 LOC). Figure 1 shows boxplots to illus-
builtins using undocumented internal builtins; this was a poten- trate the builtin use by the projects, and breaks their use up into
tial problem in our study, as public and internal builtins would be architecture-specific and architecture-independent uses, consid-
counted as separate even if they implemented the same semantics. ering both unique and non-unique builtin occurrences within a
However, since the number of internal builtins actually used was project.
relatively small, we did not attempt to match public builtins with Non-unique occurrences. The median number of builtin calls
internal ones in our quantitative analysis. in a project that used builtins was 9, the average was 173, indicating
Searching within the Projects. For each analyzed project, we that there were outlier projects that used a large number of builtins.
searched all its C files for the names of the 12,339 builtins described In projects that used builtins, architecture-specific builtins were
by the GCC documentation or used in the GCC source code. Note employed in greater numbers (median = 69); in contrast, when
that we considered only occurrences where the builtin name was architecture-independent builtins were used, their numbers were
not a substring of another identifier. For each builtin that we found, far lower (median = 7). However, since use of architecture-specific
we created a record in our database, thus obtaining 659k builtin builtins is limited to fewer projects (see Section 3.2), the overall
entries. result is dominated by the architecture-independent builtins. We
Excluding builtin use records. We used several strategies to investigated the 15 projects with the highest numbers of builtins and
eliminate false positives in the builtin use records. While investi- found that audio/video players and codecs lead the ranking (9/15),
gating the projects with the highest numbers of unique builtinsÐ followed by operating systems (3/15), a game engine, a software
mostly operating systemsÐwe found that many of them included library specialized for ARM processors, and a libc implementation.
parts of the source code of Clang or GCC, even though the projects Unique occurrences. Of the 319k builtin calls, 30k were project-
themselves were not compiler projects. Such projects were missed unique; that is, the others were duplicated within a project. The
by our prior filtering. For these projects, we excluded directories median number of unique builtins used by projects with builtins was
whose name started with gcc, clang or llvm (excluding 45% of our low, with a median of 4 and an average of 17. As with non-unique
records). builtins, projects that used architecture-specific builtins had more
We also excluded builtin occurrences that were enclosed in dou- such builtins (median = 17) than projects that used architecture-
ble quotes, as this indicates that they are part of a string literal independent builtins (median = 3). The projects that used the largest
instead of part of the code (excluding 2% of the records). To exclude number of unique builtins were, again, in most cases audio/video
builtins in comments, we did not consider builtins found in lines players and codecs (6/15). However, operating systems (2/15), game
that started with /*, *, or // (which excluded 1% of the records). engines (2/15), language implementations and compilers (2/15), a
Finally, we manually inspected a number of randomly-selected messenger, and an image codec also ranked among the top 15.
uses for each distinct builtin, which we used to create a list of 1,272 Reoccurring files. We observed that files with particular names,
one-line code fragments that indicated false positives (excluding 1% primarily header files, were more likely to contain calls to builtins.
of the records). We consider this filtering step optional, since it did One reason for this was that, consistent with findings by Lopes et
not significantly reduce the number of builtin uses. As part of this al. [28], files were copied from other projects. The majority of these
process, we detected that builtins not starting with the __builtin_ files originated either from the GNU C library glibc or from Linux-
prefix (i.e., machine-specific builtins) were likely to cause false based operating systems. While they were used primarily in oper-
positives, which is why we examined such builtin uses in detail. For ating system implementations, they were also copied to projects
example, the TI C6X architecture provided builtins like _abs, which with application code. As another example, the frequently used
often occurred in code that did not use builtins. As another example, sqlite3.c and SDL_stdinc.h files even contained the projects’
inline assembly with an instruction mnemonic that corresponded names as part of the file name: SQLite is a popular database, and SDL

76
ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia Manuel Rigger, Stefan Marr, Bram Adams, and Hanspeter Mössenböck

which communicates expected branch probabilities to the com-


●●
●●●

●●


●●●
●●●
●● ●
●●
total
piler, which can exploit this information for optimization. The

occurrences
non−unique
machine−specific ●●●
●●
__builtin_unreachable builtin can be used to silence warn-
ings by informing the compiler that code is unreachable, which
machine−independent ●
●●

●●

●●
●●
● ●●
● is useful when the compiler cannot deduce this. Some of the
category

builtins in this subcategory can also be used for metaprogram-


ming; the __builtin_constant_p builtin is resolved at com-
total ●

●●●
●●
●●● ●● ●
pile time and allows programmers to query whether a pointer

occurrences
unique
machine−specific is known by the compiler to be constant. As another exam-
ple, __builtin_types_compatible_p queries whether two input
machine−independent ●
types passed to the builtin are the same. Plain C does not offer
1 10 100 1000 10000
similar functionality.
(II) Bit and byte operations. These builtins process integers at the
Figure 1: Number of architecture-specific and architecture- level of bits and bytes. The second-most frequently used builtin was
independent builtins per project that used builtins of the re- __builtin_clz, which counts the leading zeroes in an unsigned
spective category (logarithmic scale). int; its variants for other data types also ranked among the most
commonly used builtins overall. Similarly frequent were builtins for
computing the position of the least significant one-bit, for counting
a commonly used media library. In other cases, duplicate file names the number of one-bits in an integer, and for reversing the bytes of
indicated the use case for the builtin use. For example, builtin-based an integer. We believe that these builtins were used for convenience
atomicity support was often implemented in files named atomic.h, and performance optimizations, as the same functionality could be
and math builtins were used in files named math.h. implemented in plain C.
Discussion.We found that 12,339 GCC builtins exist that tool (III) Special floating-point values. These builtins generate spe-
developers potentially need to consider, but that only about 3,000 cial values for various floating-point types. For example, the
of these are used. Although a builtin is typically found only once __builtin_inf builtin generates a positive infinity double value.
every 5,741 lines of C code, 37% of all popular projects rely on As another example, __builtin_nan returns a not-a-number value.
compiler builtins, thus strongly incentivizing their implementation Recent C standards specify macros and functions for obtaining such
in analysis and other tools. values.
(IV) Dynamic stack allocation. The __builtin_alloca builtin al-
3.2 RQ2: For what purposes are builtins used? locates the specified number of bytes of stack memory. Since C99,
To identify the purpose for which builtins are used, we explored variable length arrays have offered a similar functionality, as the
their usage at different levels of granularity: First, we examined size of an allocated array can depend on a run-time value.
in detail the usage of architecture-independent builtins and of Synchronization and atomics. After łotherž, the next com-
architecture-specific builtins, as summarized in Figure 2. Then, mon builtin category was synchronization (łsyncž) with 11 of the
we analyzed builtins that remained unused in our corpus. 50 most common builtins. In this category, the most frequently
Architecture-specific and -independent builtins. The GCC used builtin was __sync_synchronize, which issues a full mem-
documentation categorizes builtins into architecture-specific and ory barrier to restrict the order of execution in out-of-order CPUs.
architecture-independent ones, which we used as a basis for discus- Builtins for atomically executing operations were also common
sion. While 1,776 projects used at least one architecture-independent (e.g., __sync_fetch_and_add). These builtins were designed for
builtin, we found architecture-specific builtins in only 422 projects. the Intel Itanium ABI and were deprecated in favor of the builtins
That architecture-independent builtins are more common across contained in the łatomicž category. The builtins in the łatomicž
project was unexpected, since we found only 85k architecture- category additionally allow specifying the memory order of the
independent builtin uses, but 213k architecture-specific ones. How- operation, but were not that frequently used; nevertheless 7 builtins
ever, as discussed in Section 3.1, a project using architecture-specific of this category ranked among the 100 most common builtins. Note
builtins is likely to use more such builtins than projects that use that C11 introduced synchronization primitives, which are alterna-
architecture-independent builtins. tives to these builtins.
łOtherž builtins. The builtin category łotherž, which contained Libc functions. GCC provides builtins for many functions of
miscellaneous builtins, was the most common category of GCC the standard C libraryÐ4 such builtins were amongst the 100 most
builtins, even though it comprised only 68 builtinsÐ21 of which common builtins. An example is __builtin_memcpy, which im-
were among the 50 most frequently used. Since these builtins were plements the semantics of memcpy. The builtin version of the libc
the most common, we further analyzed their use, and classified them function is useful when compiling a program assuming a C dialect in
into the following subcategories: (I) direct compiler interaction, (II) which a function is not yet available; for example, when compiling
bit and byte operations, (III) special floating-point values, and (IV) under the C90 standard (-std=c90), the newer C99 function log2
dynamic stack allocation. cannot be used; however, the prefixed version __builtin_log2
(I) Direct compiler interaction. These builtins allow direct in- can still be used. Furthermore, they enable bare-metal programs,
teraction with the compiler, for example, to improve perfor- which are compiled freestanding and therefore do not have access
mance; the most frequently used builtin was __builtin_expect, to libc functions, unless they use compiler builtins.

77
Understanding GCC Builtins to Develop Better Tools ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia

GCC internal functions. Several builtins were used by cannot be excluded that these builtins are used by some projects
projects although they were not documentedÐ4 ranked among (or code yet to be written), the possibility that all of them are used
the top 100 frequently used builtins. These most frequently is rather low. Thus, our study provides a first step towards depre-
used builtins, namely __builtin_va_start, __builtin_va_end, cating unused builtins, and removing those builtins from the public
__builtin_va_arg, and __builtin_va_copy, were used exclu- documentation that could be considered internal.
sively to implement the vararg macros of the C standard. Unused architecture-independent builtins. None of the
Function return address and offsetof. The łintrospectionž projects used any of the 11 bounds-checking builtins for control-
categoryÐwith 3 of the top 100 builtinsÐenables programmers ling the Intel MPX-based pointer-bounds-checker instrumenta-
to query (I) the address to which a function returns and (II) the tion, which is based on a hardware extension in Intel processors.
address of the current frame (i.e., the area where local variables are One reason for this is that they are used by a pass within GCC
stored). To this end, GCC provides __builtin_return_address, and have received only little further attention [54], as Intel MPX-
__builtin_frame_address and other builtins. Another, similar based approaches perform only about as fast as pure software ap-
category is łoffsetofž with a single builtin __builtin_offsetof, proaches [41]. Four of the object-size-checking builtins were not
which was one of the top 100 builtins. It determines the offset of a used, namely a subset of those for printing format strings (e.g.,
struct or array member from the start address of the struct or array. __builtin___vfprintf_chk). The builtins of this category were
Object size and safe integer arithmetics. The builtin derived from library functions (e.g., memcpy), but require an ad-
__builtin_object_size in the łobject-sizež category enables pro- ditional size argument (e.g., __builtin___memcpy_chk). The in-
grammers to query the size of an object, which is useful when im- tended use of these builtins is to prevent buffer overflow attacks,
plementing bounds checks. To implement this builtin, GCC relies since object accesses that exceed the size of the object can be pre-
on static analysis to determine the size of an object where possible. vented. We speculate that these builtins were not frequently used
The łoverflowž categoryÐof which no builtin ranked among the because neither the C language nor builtins provide the function-
top 100Ðprovides wraparound semantics for overflow in signed- ality to reliably query the size of an object, which would require
integer operations (e.g., __builtin_add_overflow for addition), run-time support [55].
which would otherwise induce undefined behavior in C [9]. None of the 13 builtins of the Cilk Plus C/C++ language exten-
Usage of architecture-specific builtins. Of the 100 most- sions [18], which offer a mechanism for multithreading, were used.
frequent builtins, 44 were specific to an architecture. Most frequent In 2017, Cilk Plus was deprecated, and in November 2017 GCC
were the builtins for the PowerPC familyÐ17 of which were among removed its implementation [22]. Of the prefixed libc functions,
the top 100 builtins. The most frequent PowerPC builtins were 37% were unused. Most programs are probably compiled in hosted
those implementing vector operations such as vec_perm, which mode, where compilers can substitute calls to the libc functions
implements a vector permutation. The second category were ARM with these builtins. Another reason could be that some of them are
C NEON extensionsÐ25 of which were among the top 100 builtinsÐ used only internally. Nevertheless, they were documented in the
that also implement vector operations. On x86, which ranked next, public API.
the most common builtin was __builtin_cpu_supports followed Of the unused builtins in the łotherž category, the majority
by __builtin_cpu_init, which allow programmers to query the were narrowly specialized builtins such as __builtin_inffn,
availability of CPU features such as SIMD support. In x86-64 in- which generates an infinity value for the data type _Floatn.
line assembly, the equivalent cpuid instruction ranked among the Further, __builtin___clear_cache for flushing the pro-
most commonly used instructions [53]. Other x86 builtins were cessor’s instruction cache remained unused. The unused
quite diverse and less frequent. For brevity, the less frequently used __builtin_call_with_static_chain enables calls to languages
architecture-specific builtin categories are omitted. However, they that expect static chain pointers, such as Go.
are included in the full list of commonly used builtins in the online Discussion. The use cases for builtins were diverse. The use of
appendix. GCC builtins was dominated by architecture-independent builtins
Unused builtins. To identify unused builtins, we considered for direct interaction with the compiler, for bit-and-byte operations,
only those described in the GCC documentation (i.e., the public atomic operations, and libc equivalents. Depending on the tool,
ones). Surprisingly, we found that half of them, namely 3,033 (50%), different builtin categories could be supported to different degrees;
were not used in our corpus. The distribution differed between for example, static analysis tools that do not analyze the semantics
architecture-specific and architecture-independent builtins. From of multithreaded atomic operations might eschew implementing
the architecture-independent builtins, 379 of 560 were used, which those. Architecture-specific builtins were used by fewer projects,
corresponds to 32% unused builtins. We characterize these unused but, within these projects, in greater number than architecture-
builtins below. From the architecture-specific builtins, only 2,627 independent builtins. They were used for SIMD instructions, to
of 5,480 builtins were used, which means that more than half of determine CPU features, and to access platform-specific registers.
them (52%) were not used in any project; this is why we do not
characterize them in detail.
We contacted the GCC developers to report our findings [51];
3.3 RQ3: How many builtins must be
they responded that builtins could not be removed from the doc- implemented to support most projects?
umentation due to vendor guarantees (for architecture-specific In order to provide tool developers with a recommended implemen-
builtins) and because they might still be used in closed-source soft- tation order for builtins, we considered two implementation sce-
ware or by projects not hosted on GitHub. While the possibility narios. The first scenario considered all builtins as implementation

78
ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia Manuel Rigger, Stefan Marr, Bram Adams, and Hanspeter Mössenböck

architecture−independent architecture−specific
1500
# projects

1000

500

he
r nc c al s ic et
o iz w to
r ec ns 86 ha fin rit gx on arc tus s−II 430 ions sim dsp avr ther ions rpc mz ons
ot sy lib rn es om −s flo c tiv io x alp ack d−w ile− ngs ta io p t − − e te ti
r− te dr at of
fs ct er ve al ens o s
e in ad bj
e ov − bl ea t o −s n s ac ps ps s− n ow ys ac
th c t −l
o nt − m ans mi mi ip exte p 0−s ans
o CC o
e rp −ex v −r s p oi ltera t r m − 9 tr
G w c fr− ip g− a c− rit
y s3 86−
po rm− m
tin e rp cu x
a a w e
lo −s
−f po
ar
m −m
v8
m
ar

Figure 2: The number of projects that rely on architecture-independent and architecture-specific builtins.

candidates. The second considered only architecture-independent 100

builtins, which can be relevant when only a subset of architec-


tures is to be supported. Additionally, we assumed two pragmatic

supported projects
75

percentage of
strategies for the order of implementation: an order based on the
frequency of builtins, and one based on a greedy algorithm. Note frequency
50
that this paper assumes equal weights across projects, since weights frequency
(machine−independent)
would have biased the results based on assumptions that might not
greedy
hold for all tools. 25
greedy
Frequency order. Using this strategy, we assumed that the (machine−independent)
builtins used by the highest number of projects are to be imple-
1 10 100 1000 3000
mented first. Thus, this strategy follows the order given by Table 2.
# implemented builtins
This order is not generally optimal, because it does not take into
account that, in order for a project to be supported, all builtins used Figure 3: The numbers of builtins needed to support an in-
must be implemented. creasing number of projects increases exponentially; note
Greedy order. For rapid experimentation, it can be beneficial to the exponential x-axis.
quickly support as many projects as possible. To this end, we imple-
Table 2: The 10 most frequent builtins.
mented a greedy order where the next builtin to be implemented is
selected such that it enables support of the largest number of addi- builtin category projects
tional projects. If no such builtin exists, the next builtin is selected __builtin_expect other (compiler interaction) 890 / 48.3%
using the frequency order. __builtin_clz other (bitwise operation) 536 / 29.1%
__builtin_bswap32 other (bitwise operation) 483 / 26.2%
Results. Implementing builtins takes an exponential implemen- __builtin_constant_p other (compiler interaction) 430 / 23.3%
tation effort in terms of number of builtins that must be imple- __builtin_alloca other (stack allocation) 373 / 20.2%
__sync_synchronize sync 356 / 19.3%
mented to support a specific number of projects (see Figure 3). __builtin_bswap64 other (bitwise operation) 347 / 18.8%
The greedy order for implementing builtins performs better than __sync_fetch_and_add sync 332 / 18.0%
the frequency order, a trend that is more clear-cut when consid- __builtin_ctz other (bitwise operation) 324 / 17.6%
__builtin_bswap16 other (bitwise operation) 304 / 16.5%
ering all builtins rather than just architecture-independent ones.
To support half of the projects, in both scenarios and using both
strategies, no more than 32 builtins need to be implemented. Note
that these builtins are all architecture-independent ones; this is
3.4 RQ4: How does builtin usage develop over
expected, because, as described in Section 3.1, projects rely less
frequently on architecture-specific builtins, but if they do, they use time?
a larger number of such unique builtins. To understand whether builtin usage is an ongoing concern of
Supporting 90% of the projects requires 106 builtins to be imple- software projects or just a form of technical debt (introduced tem-
mented for the greedy approach and 112 builtins for the frequency porarily before being removed), we studied the development of
strategy when considering only architecture-independent builtins. builtin usage over time in the projects that used builtins. For this,
When considering all builtins, more than 850 builtins must be im- we analyzed all commits by iterating from the latest commit to
plemented for the frequency strategy, and more than 600 for the the oldest commitÐincluding merge commits (represented by the
greedy strategy. To support 99% of the projects, the greedy algo- union of all commits that are merged)Ðalways by following the
rithm is better: when considering only architecture-independent first parent (i.e., staying on the master branch). We considered only
builtins, around 250 instead of 300 builtins must be implemented, those projects for further inspection that had at least five commits
compared to 1,600 instead of 3,000 builtins when considering all that introduced or removed calls to builtins, since projects with
builtins. Thus, we suggest that tool developers use a greedy ap- fewer commits made it difficult to judge a project’s development
proach when implementing builtins. trend. This left us with 677 projects, 37% of the projects for which
we processed the builtin history.

79
Understanding GCC Builtins to Develop Better Tools ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia

Table 3: Builtin trends in projects.


by commit messages such as ładd atomic.h that wraps GCC atomic
trend classification #/% projects median operationsž or łCopy over stdatomic.h from freebsd.ž
commits
Builtins, both architecture-specific and -independent ones, were
mostly increasing 250 37% 18 often used for performance optimizations. Example architecture-
Increasing
stable, then increasing 17 3% 14
independent optimizations are łpopcount() optimization for speedž
increasing, then stable 140 21% 12
Stagnant spike, then stable 24 4% 8 (using __builtin_popcount), łUse __builtin_expect in scanline
mostly stable 6 1% 10 drawers to help gcc predict branchingž, and łA prefetch of status-
Decreasing 93 14% 16 >last_alloc_tslot saved 5%ž (using __builtin_prefetch). Exam-
Inconclusive 147 22% 14 ples of architecture-specific builtin commits were łVP9 common for
ARMv8 by using NEON intrinsicsž and ł30% encoding speedup: use
NEON for QuantizeBlock()ž.
Builtins were also used when they conveniently provided re-
quired functionality in commits such as łbitmap ś Add few helpers
Manual inspection methodology. We manually classified for [bit] manipulationsž. They were often used for atomics, as in
the 677 projects based on their trends of adding and removing łGCC 4.1 builtin atomic operationsž and łAdding atomic bitwise oper-
builtins. Since manual classification of trends is partly subjective, ations api and rwlocks supportž. They enabled metaprogramming
we performed manual classification based on łnegotiated agree- techniques, for example, by enabling macros to handle various data
mentž [4, 32]. Basically, the three authors jointly open-coded the types: łutil: Ensure align_power2() works with things other than uint.
qualitative data sources, arriving at a classification through consen- This uses a [cascading] set of if (__builtin_types_compatible_p())
sus. Given the lack of pre-existing classifications, such an approach statements to pick the correct alignment function tailored to a specific
seems justified. In particular, the three authors first independently type [...]ž.
classified a fixed set of 15% randomly-selected projects with respect Finally, builtins were employed to reduce the usage of assembly
to their builtin trends. In 36% of the cases, all three authors agreed and inline assembly in commits such as łavoid inline assembly in
on the classification. In 46% of the cases, two authors agreed. In 18% favor of gcc builtin functionsž and łPadlock engine: make it indepen-
of the cases, all authors disagreed. Subsequently, the three authors dent of inline assembler.ž, or as an alternative to architecture-specific
discussed diverging classifications and came to a consensus for each system libraries, such as łalloca fallback for gccž, which added a use
of them. As with other studies [10, 27], this initial classification of __builtin_alloca when the platform did not provide a header
served as a łcalibration phasež for a single author to classify the file that implements alloca.
remaining trends. Builtin removals. Removals of third-party libraries accounted for
Classification Results. The final classification consisted of four the most significant number of removals of builtins, as indicated
main categories of trends (see Table 3). Most prevalent was the by commits such as łRemove thirdpartiesž or łRemoved outdated
Increasing trend, which we assigned to projects that mostly added headers and libraries.ž Individual files or functions that used builtins
builtins (39%). The majority of those showed a clear increasing were removed as side effects of refactoring or cleanup in commits
trend (37%), while few had an initial stable period that was followed with messages such as łGeneral cleanup of the codebase, remove
by an increasing trend (3%). The second most common trend was redundant files.ž or łtools: Remove unused code.ž Auto-generated
the Stagnant trend (25%) for those projects that initially had builtin- files were removed, for instance, in the commit łRemoved getdate.c
related commits, but then did not show any or few further changes as it is regenerated from getdate.yž.
to the usage of builtins. Most Stagnant projects initially added A number of removals were related to technical debt [7]. Projects
builtins, then became stagnant (21%). Others initially added builtin removed builtins for old architectures for which they dropped sup-
uses, but then removed all or many of them shortly afterwardsÐ port, for instance, in łavr32: Retire AVR32 for good. AVR32 is gone.
a development to which we refer as a spikeÐand subsequently [...]ž or łBlackfin: Remove. The architecture is currently unmain-
showed none or few further changes (4%). A low number of Stagnant tained, removež. In other cases, builtins for certain architectures
projects exhibited a mostly stable trend overall (1%). We assigned were removed due to their maintenance effort: łRemove support for
the Decreasing trend to projects that initially had an increasing altivec using gcc builtins, since these keep changing across gcc versions.
trend followed by a decreasing trend (i.e., the removal of builtin [...]ž. Uses of builtins were hidden behind a macro, to concentrate
uses, 14%). Finally, we assigned the Inconclusive trend to projects their use to a single location in the source code: łConvert remain-
for which we could not clearly assign a trend (e.g., because they ing __builtin_expect to likely/unlikely [...]ž (for __builtin_expect)
exhibited a combination of trends, 22%). and łUse the new sol-atomic.h API instead of directly GCC intrinsicsž
Reasons for builtin additions or removal. We attempted to (for atomic operations).
find reasons for changes in the numbers of builtins, for which we In other cases, a use of __builtin_expect was removed because
analyzed commit messages and commit changes, then identified it did not improve performance: ł[...] It had no reliably measurable
common cases. performance improv[e]ment, at least on an i7 960 and within a mi-
Builtin additions. The majority of sharp increases in the number crobenchmark.ž.
of builtins was caused by the inclusion of third-party libraries that Case study. Finally, we examined the builtin development in
call builtins internally, as indicated by commits such as łupdate four projects whose trends we considered both representative and
packaged sqlite to 3.8.11.1ž or łAdded latest stb_image.ž In some insightful for our case study (see Figure 4). First, we selected libucl,
cases, only single existing header files were included, as indicated

80
ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia Manuel Rigger, Stefan Marr, Bram Adams, and Hanspeter Mössenböck

libucl libav tinycbor sheepdog


● ● ●●● ● ● ●
nr_builtins

●●
● ●
●●
● ●●
●●● ●●●● ●●
●● ●●

●● 15
3000 ●
● ● ●
7.5 ● ●●
● ● ●
7.5 ●
● ●
● ●●●●●●●●●●● ●●●●
●● ● ●
5.0 ● 2000 ● 10 5.0


● ● ● ●
● ●
● 5 ●
2.5 ● 1000 ●●●● ● 2.5 ●


● ●
● ● ●
0.0 ● 0 ● ●

● 0 ● 0.0 ●

2014 2015 2016 2017 2005 2010 2015 2015−07 2016−01 2016−07 2017−01 2010 2012 2014 2016

date

Figure 4: Builtin development in tinycbor, hashcat, libav, and libucl.

a configuration library parser, which is representative of the In- the __builtin_unreachable builtin was used to annotate the case
creasing trend. Like the majority of projects that we examined, it that should not happen as undefined, allowing the compiler to
added a small number of builtin calls for various tasks. We selected generate more efficient code. To support byteswap operations on
libav, a collection of cross-platform tools to process multimedia non-Linux systems, where the endian.h header file is typically not
formats and protocols, to represent the Decreasing category. As is present, a use of __builtin_bswap64 was added. A subsequent
typical of a media library, it contained a number of builtin-related commit also introduced byteswap uses for Linux systems, with
commits that improved performance by adding calls to architecture- the commit message stating that it was more efficient and made
specific builtins, but also systematically removed them to reduce cross-building the project easier. The __builtin_add_overflow
maintenance effort. We selected tinycbor, a library for encoding was added to implement an addition that does not cause undefined
and decoding the CBOR format, to represent the Stagnant trend. behavior on overflow [9]. Three commits that did not change the
Specifically, we classified it as increasing, then stable. Finally, we se- number of used builtins adjusted the conditions when builtins were
lected sheepdog, a distributed storage system for the QEMU virtual used due to portability reasons. For example, according to the com-
machine, which we classified as Inconclusive, due to its łpit shapež mit messages, builtin_bswap16 was added with GCC 4.8 and ICC
in the center of the plot. did not support __builtin_add_overflow, making it necessary to
libucl (Increasing). The builtin additions in libucl were in most check for these cases using macros. While the last builtin-related
cases related to hashing. The first two builtin-related commits of commit was in 2015, the project continued to be active until 2017.
libucl imported a hash algorithm from third-party libraries that sheepdog (Inconclusive) In sheepdog, the prominent increase
used __builtin_clz and __builtin_swap32 in their hashing com- before the pit was caused by a commit that replaced mutex locks by
putations. Subsequently, a third-party library hashing implemen- equivalent synchronization builtins, as it was stated to make the exe-
tation was replaced with a custom implementation, removing a cution faster. The uses were then replaced with calls to an external li-
builtin use. Subsequent commits were also related to finding bet- brary that offered equivalent functionality, resulting in the sharp de-
ter hashing algorithms, resulting in additions of calls to byteswap crease. Other commits replaced an assembly fragment that obtained
builtins and checks for SIMD support using __builtin_cpu_init the address of the frame pointer with __builtin_frame_address
and __builtin_cpu_supports. Additionally, the library added a for logging. The builtin in turn was replaced by invoking gdb to
reference-counting scheme to free memory when an allocation is perform this action. The performance of logging was improved by
no longer referenced, whose implementation depended on atomics. __builtin_expect, which was used to annotate code to assume
libav (Decreasing). In the first half of libav’s development, its the standard logging level. Besides, bit operations were simplified
use of builtins mainly increased, mostly due to Altivec-specific using __builtin_clzl and __builtin_ffsl.
builtins used to optimize computation-intensive operations, but also Discussion. We analyzed the development history of builtins
due to architecture-specific builtins of other architectures such as in projects and found that many projects mostly added calls to
PowerPC or ARM. In a few cases, calls to architecture-independent builtins. They were added for performance optimizations, atomic
builtins were added, for example for atomics. In the second half implementations, to enable metaprogramming techniques, and oth-
of the project, refactorings reduced the number of builtin calls. In ers; they were removed, for example, due to their maintenance cost
2009, calls to 236 Altivex-specific builtins were removed to reduce and through refactorings. Overall, it seems that compiler builtins
technical debt and improve the maintainability of the Snow codec are not a legacy feature from times when compilers applied less
(which was removed in 2012): łRemove AltiVec optimizations for sophisticated optimizations; tool developers must expect that con-
Snow. They are hindering the development of Snow, which is still temporary and future code will use them.
in flux.ž In 2012, calls to 233 builtins were removed as part of a The four representative projects gave insights into how projects
cleanup that dropped an unused function; in the same year, a library added and removed builtin uses. Like the majority of projects we
was removed that used 469 builtins. In 2013, another smaller, but examined, libucl, tinycbor, and sheepdog had few commits related
interesting, commit removed calls to 23 Alpha-specific builtins, to architecture-independent builtins. These builtins were used in
as the platform was no longer considered important: łRemove all various use cases, for instance, to improve the performance of code,
Alpha architecture optimizations. Alpha has been end-of-lifed and no to test for CPU features, to implement hash computations, and as
more test machines are available.ž a fallback when architecture-specific builtins were missing. Libav
tinycbor (Stagnant) The initial commit introduced macros for was one of the relatively few projects that had a large number of
performance optimizations that used __builtin_expect to com- commits related to architecture-specific builtins, and it reduced
municate branch probabilities to the compiler; one of the macros their number during code refactorings. For sheepdog and libav,
was used to annotate an error handling case as unlikely. Similarly, builtins were also removed to reduce technical debt; in sheepdog,

81
Understanding GCC Builtins to Develop Better Tools ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia

TCC 0.9.27 (2017) __builtin_types_compatible_p builtins produced incorrect re-


CompCert 3.3 (2018) sults [46]. Cilly also failed on 34 atomic test cases, on 15 test cases
KCC 1.0 (2018) due to a failure to parse a system library, on 5 test cases due to
Cilly 1.7.3 (2014)
Frama−C Chlorine−20180501 (2018)
unrecognized builtins, and on 4 test cases due to warnings for the
DragonEgg 3.3 (2013) long double type.
Sulong c710bf2 (2017) Source-to-source translators. We evaluated DragonEgg,
KLEE 1.4 (2017) which compiles source languages supported by GCC to LLVM IR.
ICC 18.0.3 (2018)
Clang 5.0 (2017)
Although it has not been updated for several years, it successfully
GCC 7.2 (2017) executed more than two thirds of the test cases. It failed to translate
0 25 50 75 100
more recent builtins (e.g., from the łatomicž category) that were
Executed test cases added to GCC after the last commit in DragonEgg.
Static analysis. We tested Frama-C [8, 21], a static-analysis
Correct Other error Missing Incorrect
framework. By default, it assumes code to be portable, and supports
Figure 5: The test-case results before bugs were fixed or compiler extensions only with an option. For 41 test cases, Frama-
builtins implemented. The order of the legend items cor- C’s analysis did not trigger a warning or error [48]. 9 test cases
responds to the order of the stacked plots. łOther errorsž failed because its standard library lacked macros for INFINITY and
refers to failed test cases unrelated to builtin support. NAN, which were used in the test cases. 14 test cases for __sync
builtins were generally supported, but incorrectly implemented for
the long type. Furthermore, __builtin_object_size referred to
builtins were replaced by using an external library instead, and in an undefined variable in its macro, which resulted in an error.
libav they were removed since an outdated architecture was no Alternative execution environments. We tested Sulong [52,
longer supported. 56], an interpreter with dynamic compiler for LLVM-based lan-
guages, and KCC [12, 16], a commercial interpreter for C that was
3.5 RQ5: How well do tools support builtins? automatically derived from a formal semantics for C and detects Un-
To determine how well current tools support GCC builtins, we man- defined Behavior. Sulong successfully executed all but two test cases,
ually implemented a builtin test suite for the 100 most commonly namely for __builtin_fabsl and __builtin___clear_cache,
used architecture-independent builtins (cf. RQ2), which would sup- which were not implemented [43]. Note that we found these er-
port the architecture-independent portion of almost 90% of the rors with a preliminary version of the test suite, and consequently
builtin-using projects (see Section 3.3). For each builtin, we used its contributed implementations for the two missing builtins.
documentation to determine both typical inputs and corner cases, KCC successfully executed test cases for 10 builtins, but, since
then wrote test cases for them. As tools to be tested, we selected pop- it is based on CIL, it had the same error in the implementation of
ular and widely used mature compilers, special-purpose compilers, the __builtin_types_compatible_p builtin. The KCC developers
source-to-source translators, alternative execution environments, also mentioned that they have łrecently been trying to add more
and static analysis tools. Figure 5 shows the results. supports for gnuc builtins.ž [47].
Mature compilers. We tested the most widely used open- Symbolic execution engine. We tested KLEE [3], a symbolic
source compilers on Linux, GCC and Clang [24], as well as the execution for LLVM-based languages. KLEE executed all test cases
commercial ICC. They all executed the test cases successfully. successfully when executed with concrete inputs.
Special-purpose compilers. We tested the special-purpose Discussion. Our findings indicate that mature compilers sup-
compilers CompCert [25, 26] and TCC. CompCert is a compiler port builtins, which is expected, since many projects rely on them.
used in safety-critical applications and has been formally verified to However, many other tools lack builtin implementations or have er-
be correct, which, however, excludes its implementation of builtins. rors in their implementations. Builtin implementations can typically
We found that CompCert correctly executed only 9 builtin test not be reused due to different tools’ use cases and implementation
cases, supporting 5 out of the 10 most frequently used builtins. languages. For example, while GCC translates builtin usages to effi-
Both __builtin_clzl and __builtin_ctzl computed an incor- cient machine code in its C/C++ source code, Frama-C abstractly
rect result for large input values [49]. After reporting the bugs reasons about them using OCaml. Tools based on existing mature
detected by our test suite, they were fixed within a day with the compiler infrastructureÐsuch as KLEE and Sulong, which are based
note that łwe need more testing herež. on LLVMÐseem to have a better builtin support, partly because
The TCC compiler is a small compiler developed to some builtins are handled by the compiler’s front end.
compile code quickly. It successfully ran only six builtin
test cases. While most tests failed with a build error, the
__builtin_types_compatible_p builtin produced an incorrect 4 THREATS TO VALIDITY
result when comparing enumerations [50]. Internal Validity. The main threat to internal validity is that we
C front end. The C Intermediate Language (CIL) [39] is a relied on a source-based heuristic approach to determine the us-
front end for the C language that facilitates program analy- age of GCC builtins, namely by searching for identifiers of known
sis and transformation. We tested its driver, called cilly, which builtins in the source files. We could have mistakenly recorded a
can also be used as a drop-in replacement for GCC. It success- builtin use when the builtin was enclosed in a comment, or when
fully executed 40 builtin test cases. The __builtin_bswap16 and an identifier with the same name as a builtin was used for another

82
ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia Manuel Rigger, Stefan Marr, Bram Adams, and Hanspeter Mössenböck

purpose. However, as described, we used several mitigation strate- best of our knowledge, a study of the usage of compiler builtins has
gies to address such łdeceivingž uses. Conversely, we could have not yet been conducted, and as such fits into the line of research
missed builtin uses if their names consisted of strings that were con- into C programming language features.
catenated by using preprocessor macros; however, we expect such
uses to be uncommon. RQ4 required manual effort for classifying
projects based on their use of builtins as they evolved, and selecting 6 CONCLUSIONS
representative projects, which is both difficult to reproduce and We have presented an empirical study of the usage of GCC builtins
subjective. To address this, we had a calibration phrase where three in a corpus of 4,912 open-source C projects retrieved from GitHub.
authors performed a classification of 15% of the projects. To the best of our knowledge, this is the first study of compiler
Construct Validity. The main threat to construct validity is builtins despite them having existed in GCC for 30 years. We believe
that the implementation order we suggest might not reflect the that they warrant investigation, since more than 12,000 builtins
needs of developers. In all implementation scenarios, we assumed exist that tools could support and because even safety-critical tools
that each project has equal weights. In practice, tool developers such as the CompCert compiler have bugs in the implementations
might prioritize one project domain over another, and might thus of common builtins.
implement builtins in a different order. We consider equal weights Implications for tool builders. Since 37% of all popular
as a neutral and simple metric; if not applicable, developers can use projects relied on compiler builtins, any tool that processes C code
our artifact to determine a better-suited order. needs to deal with them. However, since only about 3,000 of 12,339
External Validity. Several threats to external validity are re- builtins were used, it might not be necessary to implement all
lated to our study’s scope. C++ code can access GCC builtins, to builtins. In fact, we found that architecture-independent builtins
which our results might not generalize. We analyzed open-source are most commonly used and by implementing only 32 of such core
projects, hence our findings might not apply to proprietary projects. builtins, half of the projects can be supported. Since the majority of
Furthermore, they do not necessarily apply to projects hosted on projects mostly added builtin usages, tools are likely still expected
sites other than GitHub; this biases our results as, for example, GNU to support builtins for code yet to be written.
projects other than GCC are often hosted on Savannah and could Implications for the GCC developers. We think that our
potentially rely more strongly on GCC builtins. Additionally, our study is also informative for compiler developers, especially those
results cannot be generalized to the builtins of other compilers. Fi- of GCC. This study demonstrated the large scope of GCC builtin
nally, we investigated the usage of builtins at the source level, which usage and might encourage compiler developers to add, maintain,
might be different from the usage in the compiled binary (e.g., be- and document builtins in a consistent and structured way. In par-
cause their usage could be influenced by macro metaprogramming) ticular, we think that public and internal builtins should be strictly
and the usage during execution of the program. separated. Since our study highlighted the builtins that remained
unused in our data set, such builtins could potentially be considered
as deprecation candidates. As part of our future work, we want
5 RELATED WORK to engage with the GCC developers to discuss how the identified
Studies of inline assembly and linkers. Besides compiler problems could be addressed.
builtins, C projects also contain other elements not specified by the Implications for application developers. Furthermore, our
C standard. Rigger et al. found that around 30% of popular C projects study informs application developers about downsides of using
use x86-64 inline assembly [53]. The current paper demonstrates builtins. Although supported by mature compilers, GCC builtins
that GCC builtins are used more frequently than inline assembly, are a language extension that are not supported by all tools (e.g.,
which provides even stronger incentives to implement support by CompCert, TCC, KCC, and Frama-C). Thus, a reliance on builtins
C tools. Other studies focused on the role of linkers [20] and the means that fewer code analysis and other tools can be used on such
preprocessor [13]. C projects are often built using Makefiles, whose applications. Furthermore, projects that rely on internal builtinsÐ
feature usage has also been investigated [29]. such as those for variadic arguments handlingÐadd an additional
Studies of other language features. This paper fits into a re- level of technical debt, as they should only be used within GCC
cent stream of empirical studies of programming language fea- and can, in theory, change without notice. Thus, we recommend
ture usage, all of which share a methodology of mining software application developers to use builtins with caution.
repositories to determine the popularity of features in large sets of Implications for language designers. We believe that our re-
open-source projects and/or evaluate the łharmfulnessž of features sults are also useful to language designers, as they show which
in terms of potential for bugs. Most of this work has focused on functionality plain C lacks, and what potential implications adding
general-purpose programming languages, and research has evolved compiler builtins has on the projects developed in a given language.
from more common to lesser known features. For example, for Java,
the usage of general language features [11, 44], fields [62], inher-
itance [61], exception handling [1, 38, 57], lambda features [30] ACKNOWLEDGMENTS
and async constructs on Android [40] have been studied. For C++ We thank the anonymous reviewers for their valuable comments
projects, the usage of templates [63], generic constructs [60], concur- and suggestions to improve the quality of the paper. We thank
rency constructs [64] and asserts [5] have been studied. The latter Ingrid Abfalter for proofreading an early draft of this paper. The
also considered C projects, similar to Nagappan et al.’s study [34] of authors from Johannes Kepler University Linz are funded in part
the usage and harmfulness of the goto construct. However, to the by a research grant from Oracle.

83
Understanding GCC Builtins to Develop Better Tools ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia

REFERENCES and Proofs (CPP ’15). ACM, New York, NY, USA, 15ś27. https://doi.org/10.1145/
[1] Muhammad Asaduzzaman, Muhammad Ahasanuzzaman, Chanchal K. Roy, and 2676724.2693571
Kevin A. Schneider. 2016. How Developers Use Exception Handling in Java?. In [24] Chris Lattner and Vikram Adve. 2004. LLVM: A Compilation Framework for
Proceedings of the 13th International Conference on Mining Software Repositories Lifelong Program Analysis & Transformation. In Proceedings of the International
(MSR ’16). ACM, New York, NY, USA, 516ś519. https://doi.org/10.1145/2901739. Symposium on Code Generation and Optimization: Feedback-directed and Runtime
2903500 Optimization (CGO ’04). IEEE Computer Society, Washington, DC, USA, 75ś.
[2] Hudson Borges, André C. Hora, and Marco Tulio Valente. 2016. Understanding [25] Xavier Leroy. 2009. Formal Verification of a Realistic Compiler. Commun. ACM
the Factors That Impact the Popularity of GitHub Repositories. In 2016 IEEE 52, 7 (July 2009), 107ś115. https://doi.org/10.1145/1538788.1538814
International Conference on Software Maintenance and Evolution, ICSME 2016, [26] Xavier Leroy. 2009. A formally verified compiler back-end. Journal of Automated
Raleigh, NC, USA, October 2-7, 2016. 334ś344. https://doi.org/10.1109/ICSME. Reasoning 43, 4 (2009), 363ś446.
2016.31 [27] Matthew Lombard, Jennifer Snyder-Duch, and Cheryl Campanella Bracken. [n.d.].
[3] Cristian Cadar, Daniel Dunbar, and Dawson Engler. 2008. KLEE: unassisted Content Analysis in Mass Communication: Assessment and Reporting of In-
and automatic generation of high-coverage tests for complex systems programs. tercoder Reliability. Human Communication Research 28, 4 ([n. d.]), 587ś604.
In Proceedings of the 8th USENIX conference on Operating systems design and https://doi.org/10.1111/j.1468-2958.2002.tb00826.x
implementation (OSDI’08). USENIX Association, Berkeley, CA, USA, 209ś224. [28] Cristina V. Lopes, Petr Maj, Pedro Martins, Vaibhav Saini, Di Yang, Jakub Zitny,
[4] John L. Campbell, Charles Quincy, Jordan Osserman, and Ove K. Pedersen. 2013. Hitesh Sajnani, and Jan Vitek. 2017. DéJàVu: A Map of Code Duplicates on
Coding In-depth Semistructured Interviews: Problems of Unitization and Inter- GitHub. Proc. ACM Program. Lang. 1, OOPSLA (Oct. 2017), 84:1ś84:28. https:
coder Reliability and Agreement. Sociological Methods & Research 42, 3 (2013), //doi.org/10.1145/3133908
294ś320. [29] Douglas H. Martin, James R. Cordy, Bram Adams, and Giulio Antoniol. 2015.
[5] Casey Casalnuovo, Prem Devanbu, Abilio Oliveira, Vladimir Filkov, and Baishakhi Make It Simple: An Empirical Analysis of GNU Make Feature Use in Open Source
Ray. 2015. Assert Use in GitHub Projects. In Proceedings of the 37th International Projects. In Proceedings of the 2015 IEEE 23rd International Conference on Program
Conference on Software Engineering - Volume 1 (ICSE ’15). IEEE Press, Piscataway, Comprehension (ICPC ’15). IEEE Press, Piscataway, NJ, USA, 207ś217.
NJ, USA, 755ś766. [30] Davood Mazinanian, Ameya Ketkar, Nikolaos Tsantalis, and Danny Dig. 2017.
[6] Clang Team. 2018. Clang Language Extensions. Builtin Functions. https: Understanding the Use of Lambda Expressions in Java. Proc. ACM Program. Lang.
//clang.llvm.org/docs/LanguageExtensions.html 1, OOPSLA (Oct. 2017), 85:1ś85:31. https://doi.org/10.1145/3133909
[7] Ward Cunningham. 1993. The WyCash portfolio management system. 4 (04 [31] Kayvan Memarian, Justus Matthiesen, James Lingard, Kyndylan Nienhuis, David
1993), 29ś30. Chisnall, Robert N. M. Watson, and Peter Sewell. 2016. Into the Depths of C:
[8] Pascal Cuoq, Florent Kirchner, Nikolai Kosmatov, Virgile Prevosto, Julien Signoles, Elaborating the De Facto Standards. In Proceedings of the 37th ACM SIGPLAN
and Boris Yakobowski. 2012. Frama-C. In Software Engineering and Formal Conference on Programming Language Design and Implementation (PLDI ’16).
Methods, George Eleftherakis, Mike Hinchey, and Mike Holcombe (Eds.). Springer ACM, New York, NY, USA, 1ś15. https://doi.org/10.1145/2908080.2908081
Berlin Heidelberg, Berlin, Heidelberg, 233ś247. [32] Samim Mirhosseini and Chris Parnin. 2017. Can Automated Pull Requests En-
[9] Will Dietz, Peng Li, John Regehr, and Vikram Adve. 2012. Understanding Integer courage Software Developers to Upgrade Out-of-date Dependencies?. In Pro-
Overflow in C/C++. (2012), 760ś770. ceedings of the 32Nd IEEE/ACM International Conference on Automated Soft-
[10] Marcia W. DiStaso and Denise Sevick Bortree. 2012. Multi-method analysis of ware Engineering (ASE 2017). IEEE Press, Piscataway, NJ, USA, 84ś94. http:
transparency in social media practices: Survey, interviews and content analysis. //dl.acm.org/citation.cfm?id=3155562.3155577
Public Relations Review 38, 3 (2012), 511ś514. https://doi.org/10.1016/j.pubrev. [33] Nuthan Munaiah, Steven Kroh, Craig Cabrey, and Meiyappan Nagappan. 2017.
2012.01.003 Public Relations History. Curating GitHub for Engineered Software Projects. Empirical Softw. Engg. 22, 6
[11] Robert Dyer, Hridesh Rajan, Hoan Anh Nguyen, and Tien N. Nguyen. 2014. (Dec. 2017), 3219ś3253. https://doi.org/10.1007/s10664-017-9512-6
Mining Billions of AST Nodes to Study Actual and Potential Usage of Java [34] Meiyappan Nagappan, Romain Robbes, Yasutaka Kamei, Éric Tanter, Shane McIn-
Language Features. In 36th International Conference on Software Engineering tosh, Audris Mockus, and Ahmed E. Hassan. 2015. An Empirical Study of Goto
(ICSE’14). 779ś790. in C Code from GitHub Repositories. In Proceedings of the 2015 10th Joint Meeting
[12] Chucky Ellison and Grigore Rosu. 2012. An Executable Formal Semantics of on Foundations of Software Engineering (ESEC/FSE 2015). ACM, New York, NY,
C with Applications. In Proceedings of the 39th Annual ACM SIGPLAN-SIGACT USA, 404ś414. https://doi.org/10.1145/2786805.2786834
Symposium on Principles of Programming Languages (POPL ’12). ACM, New York, [35] Meiyappan Nagappan, Thomas Zimmermann, and Christian Bird. 2013. Diversity
NY, USA, 533ś544. https://doi.org/10.1145/2103656.2103719 in Software Engineering Research. In Proceedings of the 2013 9th Joint Meeting on
[13] Michael D. Ernst, Greg J. Badros, and David Notkin. 2002. An Empirical Analysis Foundations of Software Engineering (ESEC/FSE 2013). ACM, New York, NY, USA,
of C Preprocessor Use. IEEE Trans. Softw. Eng. 28, 12 (Dec. 2002), 1146ś1170. 466ś476. https://doi.org/10.1145/2491411.2491415
https://doi.org/10.1109/TSE.2002.1158288 [36] Santosh Nagarakatte, Jianzhou Zhao, Milo M.K. Martin, and Steve Zdancewic.
[14] David Evans, John Guttag, James Horning, and Yang Meng Tan. 1994. LCLint: A 2009. SoftBound: Highly Compatible and Complete Spatial Memory Safety
Tool for Using Specifications to Check Code. (1994), 87ś96. https://doi.org/10. for C. In Proceedings of the 30th ACM SIGPLAN Conference on Programming
1145/193173.195297 Language Design and Implementation (PLDI ’09). ACM, New York, NY, USA,
[15] David Evans and David Larochelle. 2002. Improving Security Using Extensible 245ś258. https://doi.org/10.1145/1542476.1542504
Lightweight Static Analysis. IEEE Softw. 19, 1 (Jan. 2002), 42ś51. https://doi.org/ [37] Santosh Nagarakatte, Jianzhou Zhao, Milo M.K. Martin, and Steve Zdancewic.
10.1109/52.976940 2010. CETS: Compiler Enforced Temporal Safety for C. Proceedings of the
[16] Chris Hathhorn, Chucky Ellison, and Grigore Roşu. 2015. Defining the Undefined- International Symposium on Memory Management 45, 8 (June 2010), 31ś40.
ness of C. In Proceedings of the 36th ACM SIGPLAN Conference on Programming [38] Suman Nakshatri, Maithri Hegde, and Sahithi Thandra. 2016. Analysis of Excep-
Language Design and Implementation (PLDI ’15). ACM, New York, NY, USA, tion Handling Patterns in Java Projects: An Empirical Study. In Proceedings of the
336ś345. https://doi.org/10.1145/2737924.2737979 13th International Conference on Mining Software Repositories (MSR ’16). ACM,
[17] Gerard J Holzmann. 2002. UNO: Static source code checking for user-defined New York, NY, USA, 500ś503. https://doi.org/10.1145/2901739.2903499
properties. In Proc. IDPT, Vol. 2. [39] George C. Necula, Scott McPeak, Shree Prakash Rahul, and Westley Weimer.
[18] Intel. [n.d.]. Cilk Plus. https://www.cilkplus.org/ 2002. CIL: Intermediate Language and Tools for Analysis and Transformation
[19] Eirini Kalliamvakou, Georgios Gousios, Kelly Blincoe, Leif Singer, Daniel M. of C Programs. In Proceedings of the 11th International Conference on Compiler
German, and Daniela Damian. 2014. The Promises and Perils of Mining GitHub. Construction (CC ’02). Springer-Verlag, London, UK, UK, 213ś228.
In Proceedings of the 11th Working Conference on Mining Software Repositories [40] Semih Okur, Danny Dig, and Yu Lin. 2015. Study and Refactoring of Android
(MSR 2014). ACM, New York, NY, USA, 92ś101. https://doi.org/10.1145/2597073. Asynchronous Programming. (2015).
2597074 [41] Oleksii Oleksenko, Dmitrii Kuvaiskii, Pramod Bhatotia, Pascal Felber, and Christof
[20] Stephen Kell, Dominic P. Mulligan, and Peter Sewell. 2016. The Missing Link: Fetzer. 2017. Intel MPX Explained: An Empirical Study of Intel MPX and Software-
Explaining ELF Static Linking, Semantically. In Proceedings of the 2016 ACM based Bounds Checking Approaches. CoRR abs/1702.00719 (2017).
SIGPLAN International Conference on Object-Oriented Programming, Systems, [42] John O’Neill. 2006. Intel Compilers for Linux: Compatibility with GNU Compil-
Languages, and Applications (OOPSLA 2016). ACM, New York, NY, USA, 607ś623. ers.
https://doi.org/10.1145/2983990.2983996 [43] Thomas Pointhuber. 2017. Add some testcases for builtins, little bugfixes (Sulong
[21] Florent Kirchner, Nikolai Kosmatov, Virgile Prevosto, Julien Signoles, and Boris GitHub Pull Request). https://github.com/graalvm/sulong/pull/807.
Yakobowski. 2015. Frama-C: A software analysis perspective. Formal Aspects of [44] Dong Qiu, Bixin Li, Earl T. Barr, and Zhendong Su. 2017. Understanding the
Computing 27, 3 (May 2015), 573ś609. https://doi.org/10.1007/s00165-014-0326-7 syntactic rule usage in java. Journal of Systems and Software 123 (2017), 160ś172.
[22] Julia Koval. 2017. remove cilk-plus. https://gcc.gnu.org/ml/gcc-patches/2017- https://doi.org/10.1016/j.jss.2016.10.017
11/msg01345.html. [45] Dan Quinlan. 2000. ROSE: Compiler Support for Object-Oriented Frameworks.
[23] Robbert Krebbers and Freek Wiedijk. 2015. A Typed C11 Semantics for Interactive In Proceedings of Conference on Parallel Compilers (CPC2000), Aussois, France
Theorem Proving. In Proceedings of the 2015 Conference on Certified Programs (Parallel Processing Letters), Vol. 10. Springer Verlag.

84
ESEC/FSE ’19, August 26ś30, 2019, Tallinn, Estonia Manuel Rigger, Stefan Marr, Bram Adams, and Hanspeter Mössenböck

[46] Manuel Rigger. 2018. GCC Builtin Support (CIL Github Bug Report). https: [57] Demóstenes Sena, Roberta Coelho, Uirá Kulesza, and Rodrigo Bonifácio. 2016.
//github.com/cil-project/cil/issues/44. Understanding the Exception Handling Strategies of Java Libraries: An Empirical
[47] Manuel Rigger. 2018. GCC Builtins (C-Semantics GitHub Bug Report). https: Study. In Proceedings of the 13th International Conference on Mining Software
//github.com/kframework/c-semantics/issues/318. Repositories (MSR ’16). ACM, New York, NY, USA, 212ś222. https://doi.org/10.
[48] Manuel Rigger. 2018. GCC Builtins Support (Frama-C Mailing List). https: 1145/2901739.2901757
//lists.gforge.inria.fr/pipermail/frama-c-discuss/2018-July/005483.html. [58] Konstantin Serebryany, Derek Bruening, Alexander Potapenko, and Dmitriy
[49] Manuel Rigger. 2018. Support of GCC Builtins (CompCert GitHub Bug Report). Vyukov. 2012. AddressSanitizer: A Fast Address Sanity Checker.. In USENIX
https://github.com/AbsInt/CompCert/issues/243. Annual Technical Conference. 309ś318.
[50] Manuel Rigger. 2018. Support of GCC Builtins (Tiny C Compiler Mailing List). [59] Evgeniy Stepanov and Konstantin Serebryany. 2015. MemorySanitizer: fast
http://lists.nongnu.org/archive/html/tinycc-devel/2018-07/msg00007.html. detector of uninitialized memory use in C++. In Code Generation and Optimization
[51] Manuel Rigger. 2018. Unused GCC builtins (GCC Mailing List). https://gcc.gnu. (CGO), 2015 IEEE/ACM International Symposium on. IEEE, 46ś55.
org/ml/gcc/2018-01/msg00166.html. [60] Andrew M. Sutton, Ryan Holeman, and Jonathan I. Maletic. 2010. Identification of
[52] Manuel Rigger, Matthias Grimmer, Christian Wimmer, Thomas Würthinger, and Idiom Usage in C++ Generic Libraries. In The 18th IEEE International Conference
Hanspeter Mössenböck. 2016. Bringing Low-level Languages to the JVM: Efficient on Program Comprehension, ICPC 2010, Braga, Minho, Portugal, June 30-July 2,
Execution of LLVM IR on Truffle. In Proceedings of the 8th International Workshop 2010. 160ś169. https://doi.org/10.1109/ICPC.2010.37
on Virtual Machines and Intermediate Languages (VMIL 2016). ACM, New York, [61] Ewan Tempero, James Noble, and Hayden Melton. 2008. How Do Java Programs
NY, USA, 6ś15. https://doi.org/10.1145/2998415.2998416 Use Inheritance? An Empirical Study of Inheritance in Java Software. In Proceed-
[53] Manuel Rigger, Stefan Marr, Stephen Kell, David Leopoldseder, and Hanspeter ings of the 22Nd European Conference on Object-Oriented Programming (ECOOP
Mössenböck. 2018. An Analysis of x86-64 Inline Assembly in C Programs. In ’08). Springer-Verlag, Berlin, Heidelberg, 667ś691. https://doi.org/10.1007/978-3-
Proceedings of the 14th ACM SIGPLAN/SIGOPS International Conference on Virtual 540-70592-5_28
Execution Environments (VEE ’18). ACM, New York, NY, USA, 84ś99. https: [62] Ewan D. Tempero. 2009. How Fields are Used in Java: An Empirical Study. In
//doi.org/10.1145/3186411.3186418 20th Australian Software Engineering Conference (ASWEC 2009), 14-17 April 2009,
[54] Manuel Rigger, Daniel Pekarek, and Hanspeter Mössenböck. 2018. Context- Gold Cost, Australia. 91ś100. https://doi.org/10.1109/ASWEC.2009.19
Aware Failure-Oblivious Computing as a Means of Preventing Buffer Overflows. [63] Di Wu, Lin Chen, Yuming Zhou, and Baowen Xu. 2014. An empirical study on
(2018), 376ś390. https://doi.org/10.1007/978-3-030-02744-5_28 the adoption of C++ templates: Library templates versus user defined templates.
[55] Manuel Rigger, Roland Schatz, Rene Mayrhofer, Matthias Grimmer, and In The 26th International Conference on Software Engineering and Knowledge
Hanspeter Mössenböck. 2018. Introspection for C and its Applications to Li- Engineering, Hyatt Regency, Vancouver, BC, Canada, July 1-3, 2013. 144ś149.
brary Robustness. The Art, Science, and Engineering of Programming 2 (2018). [64] Di Wu, Lin Chen, Yuming Zhou, and Baowen Xu. 2016. An extensive empirical
https://doi.org/10.22152/programming-journal.org/2018/2/4 study on C++ concurrency constructs. Information & Software Technology 76
[56] Manuel Rigger, Roland Schatz, René Mayrhofer, Matthias Grimmer, and (2016), 1ś18. https://doi.org/10.1016/j.infsof.2016.04.004
Hanspeter Mössenböck. 2018. Sulong, and Thanks for All the Bugs: Finding [65] Deng Xu. 2011. [Frama-c-discuss] inline assembly code. https://lists.gforge.inria.
Errors in C Programs by Abstracting from the Native Execution Model. In Pro- fr/pipermail/frama-c-discuss/2011-March/002589.html (Accessed October 2017).
ceedings of the Twenty-Third International Conference on Architectural Support for [66] Zhongxing Xu, Ted Kremenek, and Jian Zhang. 2010. A Memory Model for Static
Programming Languages and Operating Systems (ASPLOS ’18). ACM, New York, Analysis of C Programs. In Proceedings of the 4th International Conference on
NY, USA, 377ś391. https://doi.org/10.1145/3173162.3173174 Leveraging Applications of Formal Methods, Verification, and Validation - Volume
Part I (ISoLA’10). Springer-Verlag, Berlin, Heidelberg, 535ś548.

85

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy