aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--Documentation/IR.md356
-rw-r--r--Documentation/IR.rst411
-rw-r--r--Documentation/conf.py1
-rw-r--r--Documentation/doc-guide.rst4
-rw-r--r--Documentation/index.rst2
-rwxr-xr-xDocumentation/sphinx/ir.py75
-rw-r--r--builtin.c95
-rw-r--r--ident-list.h1
-rw-r--r--lib.c1
-rw-r--r--pre-process.c47
-rw-r--r--symbol.c9
-rw-r--r--symbol.h4
-rw-r--r--validation/builtin-overflow.c246
-rw-r--r--validation/preprocessor/has-builtin.c43
14 files changed, 933 insertions, 362 deletions
diff --git a/Documentation/IR.md b/Documentation/IR.md
deleted file mode 100644
index 03fa3f80..00000000
--- a/Documentation/IR.md
+++ /dev/null
@@ -1,356 +0,0 @@
-# Sparse's Intermediate Representation
-
-
-## Instruction
-This document briefly describes which field of struct instruction is
-used by which operation.
-
-Some of those fields are used by almost all instructions,
-some others are specific to only one or a few instructions.
-The common ones are:
-- .src1, .src2, .src3: (pseudo_t) operands of binops or ternary ops.
-- .src: (pseudo_t) operand of unary ops (alias for .src1).
-- .target: (pseudo_t) result of unary, binary & ternary ops, is sometimes used
- otherwise by some others instructions.
-- .cond: (pseudo_t) input operands for condition (alias .src/.src1)
-- .type: (symbol*) usually the type of .result, sometimes of the operands
-
-### Terminators
-#### OP_RET
-Return from subroutine.
-- .src : returned value (NULL if void)
-- .type: type of .src
-
-#### OP_BR
-Unconditional branch
-- .bb_true: destination basic block
-
-#### OP_CBR
-Conditional branch
-- .cond: condition
-- .type: type of .cond, must be an integral type
-- .bb_true, .bb_false: destination basic blocks
-
-#### OP_SWITCH
-Switch / multi-branch
-- .cond: condition
-- .type: type of .cond, must be an integral type
-- .multijmp_list: pairs of case-value - destination basic block
-
-#### OP_COMPUTEDGOTO
-Computed goto / branch to register
-- .src: address to branch to (void*)
-- .multijmp_list: list of possible destination basic blocks
-
-### Arithmetic binops
-They all follow the same signature:
-- .src1, .src1: operands (types must be compatible with .target)
-- .target: result of the operation (must be an integral type)
-- .type: type of .target
-
-#### OP_ADD
-Integer addition.
-
-#### OP_SUB
-Integer subtraction.
-
-#### OP_MUL
-Integer multiplication.
-
-#### OP_DIVU
-Integer unsigned division.
-
-#### OP_DIVS
-Integer signed division.
-
-#### OP_MODU
-Integer unsigned remainder.
-
-#### OP_MODS
-Integer signed remainder.
-
-#### OP_SHL
-Shift left (integer only)
-
-#### OP_LSR
-Logical Shift right (integer only)
-
-#### OP_ASR
-Arithmetic Shift right (integer only)
-
-### Floating-point binops
-They all follow the same signature:
-- .src1, .src1: operands (types must be compatible with .target)
-- .target: result of the operation (must be a floating-point type)
-- .type: type of .target
-
-#### OP_FADD
-Floating-point addition.
-
-#### OP_FSUB
-Floating-point subtraction.
-
-#### OP_FMUL
-Floating-point multiplication.
-
-#### OP_FDIV
-Floating-point division.
-
-### Logical ops
-They all follow the same signature:
-- .src1, .src2: operands (types must be compatible with .target)
-- .target: result of the operation
-- .type: type of .target, must be an integral type
-
-#### OP_AND
-#### OP_OR
-#### OP_XOR
-
-### Boolean ops
-#### OP_AND_BOOL
-#### OP_OR_BOOL
-
-### Integer compares
-They all have the following signature:
-- .src1, .src2: operands (types must be compatible)
-- .target: result of the operation (0/1 valued integer)
-- .type: type of .target, must be an integral type
-
-#### OP_SET_EQ
-Compare equal.
-
-#### OP_SET_NE
-Compare not-equal.
-
-#### OP_SET_LE
-Compare less-than-or-equal (signed).
-
-#### OP_SET_GE
-Compare greater-than-or-equal (signed).
-
-#### OP_SET_LT
-Compare less-than (signed).
-
-#### OP_SET_GT
-Compare greater-than (signed).
-
-#### OP_SET_B
-Compare less-than (unsigned).
-
-#### OP_SET_A
-Compare greater-than (unsigned).
-
-#### OP_SET_BE
-Compare less-than-or-equal (unsigned).
-
-#### OP_SET_AE
-Compare greater-than-or-equal (unsigned).
-
-### Floating-point compares
-They all have the same signature as the integer compares.
-The usual 6 operations exist in two versions: 'ordered' and
-'unordered'. Theses operations first check if any operand is a
-NaN and if it is the case the ordered compares return false
-and then unordered return true, otherwise the result of the
-comparison, now garanted to be done on non-NaNs, is returned.
-
-#### OP_FCMP_OEQ
-Floating-point compare ordered equal
-
-#### OP_FCMP_ONE
-Floating-point compare ordered not-equal
-
-#### OP_FCMP_OLE
-Floating-point compare ordered less-than-or-equal
-
-#### OP_FCMP_OGE
-Floating-point compare ordered greater-or-equal
-
-#### OP_FCMP_OLT
-Floating-point compare ordered less-than
-
-#### OP_FCMP_OGT
-Floating-point compare ordered greater-than
-
-
-#### OP_FCMP_UEQ
-Floating-point compare unordered equal
-
-#### OP_FCMP_UNE
-Floating-point compare unordered not-equal
-
-#### OP_FCMP_ULE
-Floating-point compare unordered less-than-or-equal
-
-#### OP_FCMP_UGE
-Floating-point compare unordered greater-or-equal
-
-#### OP_FCMP_ULT
-Floating-point compare unordered less-than
-
-#### OP_FCMP_UGT
-Floating-point compare unordered greater-than
-
-
-#### OP_FCMP_ORD
-Floating-point compare ordered: return true if both operands are ordered
-(none of the operands are a NaN) and false otherwise.
-
-#### OP_FCMP_UNO
-Floating-point compare unordered: return false if no operands is ordered
-and true otherwise.
-
-### Unary ops
-#### OP_NOT
-Logical not.
-- .src: operand (type must be compatible with .target)
-- .target: result of the operation
-- .type: type of .target, must be an integral type
-
-#### OP_NEG
-Integer negation.
-- .src: operand (type must be compatible with .target)
-- .target: result of the operation (must be an integral type)
-- .type: type of .target
-
-#### OP_FNEG
-Floating-point negation.
-- .src: operand (type must be compatible with .target)
-- .target: result of the operation (must be a floating-point type)
-- .type: type of .target
-
-#### OP_COPY
-Copy (only needed after out-of-SSA).
-- .src: operand (type must be compatible with .target)
-- .target: result of the operation
-- .type: type of .target
-
-### Type conversions
-They all have the following signature:
-- .src: source value
-- .orig_type: type of .src
-- .target: result value
-- .type: type of .target
-
-#### OP_CAST
-Cast to unsigned integer (and to void pointer).
-
-#### OP_SCAST
-Cast to signed integer.
-
-#### OP_FPCAST
-Cast to floating-point.
-
-#### OP_PTRCAST
-Cast to pointer.
-
-### Ternary ops
-#### OP_SEL
-- .src1: condition, must be of integral type
-- .src2, .src3: operands (types must be compatible with .target)
-- .target: result of the operation
-- .type: type of .target
-
-#### OP_RANGE
-Range/bounds checking (only used for an unused sparse extension).
-- .src1: value to be checked
-- .src2, src3: bound of the value (must be constants?)
-- .type: type of .src[123]?
-
-### Memory ops
-#### OP_LOAD
-Load.
-- .src: base address to load from
-- .offset: address offset
-- .target: loaded value
-- .type: type of .target
-
-#### OP_STORE
-Store.
-- .src: base address to store to
-- .offset: address offset
-- .target: value to be stored
-- .type: type of .target
-
-### Others
-#### OP_SYMADDR
-Create a pseudo corresponding to the address of a symbol.
-- .symbol: (pseudo_t) input symbol (alias .src)
-- .target: symbol's address
-
-#### OP_SETFVAL
-Create a pseudo corresponding to a floating-point literal.
-- .fvalue: the literal's value (long double)
-- .target: the corresponding pseudo
-- .type: type of the literal & .target
-
-#### OP_SETVAL
-Create a pseudo corresponding to a string literal or a label-as-value.
-The value is given as an expression EXPR_STRING or EXPR_LABEL.
-- .val: (expression) input expression
-- .target: the resulting value
-- .type: type of .target, the value
-
-#### OP_PHI
-Phi-node (for SSA form).
-- .phi_list: phi-operands (type must be compatible with .target)
-- .target: "result"
-- .type: type of .target
-
-#### OP_PHISOURCE
-Phi-node source.
-Like OP_COPY but exclusively used to give a defining instructions
-(and thus also a type) to *all* OP_PHI operands.
-- .phi_src: operand (type must be compatible with .target, alias .src)
-- .target: the "result" PSEUDO_PHI
-- .type: type of .target
-- .phi_users: list of phi instructions using the target pseudo
-
-#### OP_CALL
-Function call.
-- .func: (pseudo_t) the function (can be a symbol or a "register", alias .src))
-- .arguments: (pseudo_list) list of the associated arguments
-- .target: function return value (if any)
-- .type: type of .target
-- .fntypes: (symbol_list) list of the function's types: the first enrty is the full function type, the next ones are the type of each arguments
-
-#### OP_INLINED_CALL
-Only used as an annotation to show that the instructions just above
-correspond to a function that have been inlined.
-- .func: (pseudo_t) the function (must be a symbol, alias .src))
-- .arguments: list of pseudos that where the function's arguments
-- .target: function return value (if any)
-- .type: type of .target
-
-#### OP_SLICE
-Extract a "slice" from an aggregate.
-- .base: (pseudo_t) aggregate (alias .src)
-- .from, .len: offet & size of the "slice" within the aggregate
-- .target: result
-- .type: type of .target
-
-#### OP_ASM
-Inlined assembly code.
-- .string: asm template
-- .asm_rules: asm constraints, rules
-
-### Sparse tagging (line numbers, context, whatever)
-#### OP_CONTEXT
-Currently only used for lock/unlock tracking.
-- .context_expr: unused
-- .increment: (1 for locking, -1 for unlocking)
-- .check: (ignore the instruction if 0)
-
-### Misc ops
-#### OP_ENTRY
-Function entry point (no associated semantic).
-
-#### OP_BADOP
-Invalid operation (should never be generated).
-
-#### OP_NOP
-No-op (should never be generated).
-
-#### OP_DEATHNOTE
-Annotation telling the pseudo will be death after the next
-instruction (other than some other annotation, that is).
diff --git a/Documentation/IR.rst b/Documentation/IR.rst
new file mode 100644
index 00000000..67ef06a5
--- /dev/null
+++ b/Documentation/IR.rst
@@ -0,0 +1,411 @@
+.. default-domain:: ir
+
+Sparse's Intermediate Representation
+====================================
+
+Instructions
+~~~~~~~~~~~~
+
+This document briefly describes which field of struct instruction is
+used by which operation.
+
+Some of those fields are used by almost all instructions,
+some others are specific to only one or a few instructions.
+The common ones are:
+
+* .src1, .src2, .src3: (pseudo_t) operands of binops or ternary ops.
+* .src: (pseudo_t) operand of unary ops (alias for .src1).
+* .target: (pseudo_t) result of unary, binary & ternary ops, is
+ sometimes used otherwise by some others instructions.
+* .cond: (pseudo_t) input operands for condition (alias .src/.src1)
+* .type: (symbol*) usually the type of .result, sometimes of the operands
+
+Terminators
+-----------
+.. op:: OP_RET
+ Return from subroutine.
+
+ * .src : returned value (NULL if void)
+ * .type: type of .src
+
+.. op:: OP_BR
+ Unconditional branch
+
+ * .bb_true: destination basic block
+
+.. op:: OP_CBR
+ Conditional branch
+
+ * .cond: condition
+ * .type: type of .cond, must be an integral type
+ * .bb_true, .bb_false: destination basic blocks
+
+.. op:: OP_SWITCH
+ Switch / multi-branch
+
+ * .cond: condition
+ * .type: type of .cond, must be an integral type
+ * .multijmp_list: pairs of case-value - destination basic block
+
+.. op:: OP_COMPUTEDGOTO
+ Computed goto / branch to register
+
+ * .src: address to branch to (void*)
+ * .multijmp_list: list of possible destination basic blocks
+
+Arithmetic binops
+-----------------
+They all follow the same signature:
+ * .src1, .src1: operands (types must be compatible with .target)
+ * .target: result of the operation (must be an integral type)
+ * .type: type of .target
+
+.. op:: OP_ADD
+ Integer addition.
+
+.. op:: OP_SUB
+ Integer subtraction.
+
+.. op:: OP_MUL
+ Integer multiplication.
+
+.. op:: OP_DIVU
+ Integer unsigned division.
+
+.. op:: OP_DIVS
+ Integer signed division.
+
+.. op:: OP_MODU
+ Integer unsigned remainder.
+
+.. op:: OP_MODS
+ Integer signed remainder.
+
+.. op:: OP_SHL
+ Shift left (integer only)
+
+.. op:: OP_LSR
+ Logical Shift right (integer only)
+
+.. op:: OP_ASR
+ Arithmetic Shift right (integer only)
+
+Floating-point binops
+---------------------
+They all follow the same signature:
+ * .src1, .src1: operands (types must be compatible with .target)
+ * .target: result of the operation (must be a floating-point type)
+ * .type: type of .target
+
+.. op:: OP_FADD
+ Floating-point addition.
+
+.. op:: OP_FSUB
+ Floating-point subtraction.
+
+.. op:: OP_FMUL
+ Floating-point multiplication.
+
+.. op:: OP_FDIV
+ Floating-point division.
+
+Logical ops
+-----------
+They all follow the same signature:
+ * .src1, .src2: operands (types must be compatible with .target)
+ * .target: result of the operation
+ * .type: type of .target, must be an integral type
+
+.. op:: OP_AND
+ Logical AND
+
+.. op:: OP_OR
+ Logical OR
+
+.. op:: OP_XOR
+ Logical XOR
+
+Boolean ops
+-----------
+.. op:: OP_AND_BOOL
+ Boolean AND
+
+.. op:: OP_OR_BOOL
+ Boolean OR
+
+Integer compares
+----------------
+They all have the following signature:
+ * .src1, .src2: operands (types must be compatible)
+ * .target: result of the operation (0/1 valued integer)
+ * .type: type of .target, must be an integral type
+
+.. op:: OP_SET_EQ
+ Compare equal.
+
+.. op:: OP_SET_NE
+ Compare not-equal.
+
+.. op:: OP_SET_LE
+ Compare less-than-or-equal (signed).
+
+.. op:: OP_SET_GE
+ Compare greater-than-or-equal (signed).
+
+.. op:: OP_SET_LT
+ Compare less-than (signed).
+
+.. op:: OP_SET_GT
+ Compare greater-than (signed).
+
+.. op:: OP_SET_B
+ Compare less-than (unsigned).
+
+.. op:: OP_SET_A
+ Compare greater-than (unsigned).
+
+.. op:: OP_SET_BE
+ Compare less-than-or-equal (unsigned).
+
+.. op:: OP_SET_AE
+ Compare greater-than-or-equal (unsigned).
+
+Floating-point compares
+-----------------------
+They all have the same signature as the integer compares.
+
+The usual 6 operations exist in two versions: 'ordered' and
+'unordered'. These operations first check if any operand is a
+NaN and if it is the case the ordered compares return false
+and then unordered return true, otherwise the result of the
+comparison, now guaranteed to be done on non-NaNs, is returned.
+
+.. op:: OP_FCMP_OEQ
+ Floating-point compare ordered equal
+
+.. op:: OP_FCMP_ONE
+ Floating-point compare ordered not-equal
+
+.. op:: OP_FCMP_OLE
+ Floating-point compare ordered less-than-or-equal
+
+.. op:: OP_FCMP_OGE
+ Floating-point compare ordered greater-or-equal
+
+.. op:: OP_FCMP_OLT
+ Floating-point compare ordered less-than
+
+.. op:: OP_FCMP_OGT
+ Floating-point compare ordered greater-than
+
+
+.. op:: OP_FCMP_UEQ
+ Floating-point compare unordered equal
+
+.. op:: OP_FCMP_UNE
+ Floating-point compare unordered not-equal
+
+.. op:: OP_FCMP_ULE
+ Floating-point compare unordered less-than-or-equal
+
+.. op:: OP_FCMP_UGE
+ Floating-point compare unordered greater-or-equal
+
+.. op:: OP_FCMP_ULT
+ Floating-point compare unordered less-than
+
+.. op:: OP_FCMP_UGT
+ Floating-point compare unordered greater-than
+
+
+.. op:: OP_FCMP_ORD
+ Floating-point compare ordered: return true if both operands are ordered
+ (none of the operands are a NaN) and false otherwise.
+
+.. op:: OP_FCMP_UNO
+ Floating-point compare unordered: return false if no operands is ordered
+ and true otherwise.
+
+Unary ops
+---------
+.. op:: OP_NOT
+ Logical not.
+
+ * .src: operand (type must be compatible with .target)
+ * .target: result of the operation
+ * .type: type of .target, must be an integral type
+
+.. op:: OP_NEG
+ Integer negation.
+
+ * .src: operand (type must be compatible with .target)
+ * .target: result of the operation (must be an integral type)
+ * .type: type of .target
+
+.. op:: OP_FNEG
+ Floating-point negation.
+
+ * .src: operand (type must be compatible with .target)
+ * .target: result of the operation (must be a floating-point type)
+ * .type: type of .target
+
+.. op:: OP_COPY
+ Copy (only needed after out-of-SSA).
+
+ * .src: operand (type must be compatible with .target)
+ * .target: result of the operation
+ * .type: type of .target
+
+Type conversions
+----------------
+They all have the following signature:
+ * .src: source value
+ * .orig_type: type of .src
+ * .target: result value
+ * .type: type of .target
+
+.. op:: OP_CAST
+ Cast to unsigned integer (and to void pointer).
+
+.. op:: OP_SCAST
+ Cast to signed integer.
+
+.. op:: OP_FPCAST
+ Cast to floating-point.
+
+.. op:: OP_PTRCAST
+ Cast to pointer.
+
+Ternary ops
+-----------
+.. op:: OP_SEL
+ * .src1: condition, must be of integral type
+ * .src2, .src3: operands (types must be compatible with .target)
+ * .target: result of the operation
+ * .type: type of .target
+
+.. op:: OP_RANGE
+ Range/bounds checking (only used for an unused sparse extension).
+
+ * .src1: value to be checked
+ * .src2, src3: bound of the value (must be constants?)
+ * .type: type of .src[123]?
+
+Memory ops
+----------
+.. op:: OP_LOAD
+ Load.
+
+ * .src: base address to load from
+ * .offset: address offset
+ * .target: loaded value
+ * .type: type of .target
+
+.. op:: OP_STORE
+ Store.
+
+ * .src: base address to store to
+ * .offset: address offset
+ * .target: value to be stored
+ * .type: type of .target
+
+Others
+------
+.. op:: OP_SYMADDR
+ Create a pseudo corresponding to the address of a symbol.
+
+ * .symbol: (pseudo_t) input symbol (alias .src)
+ * .target: symbol's address
+
+.. op:: OP_SETFVAL
+ Create a pseudo corresponding to a floating-point literal.
+
+ * .fvalue: the literal's value (long double)
+ * .target: the corresponding pseudo
+ * .type: type of the literal & .target
+
+.. op:: OP_SETVAL
+ Create a pseudo corresponding to a string literal or a label-as-value.
+ The value is given as an expression EXPR_STRING or EXPR_LABEL.
+
+ * .val: (expression) input expression
+ * .target: the resulting value
+ * .type: type of .target, the value
+
+.. op:: OP_PHI
+ Phi-node (for SSA form).
+
+ * .phi_list: phi-operands (type must be compatible with .target)
+ * .target: "result"
+ * .type: type of .target
+
+.. op:: OP_PHISOURCE
+ Phi-node source.
+ Like OP_COPY but exclusively used to give a defining instructions
+ (and thus also a type) to *all* OP_PHI operands.
+
+ * .phi_src: operand (type must be compatible with .target, alias .src)
+ * .target: the "result" PSEUDO_PHI
+ * .type: type of .target
+ * .phi_users: list of phi instructions using the target pseudo
+
+.. op:: OP_CALL
+ Function call.
+
+ * .func: (pseudo_t) the function (can be a symbol or a "register",
+ alias .src))
+ * .arguments: (pseudo_list) list of the associated arguments
+ * .target: function return value (if any)
+ * .type: type of .target
+ * .fntypes: (symbol_list) list of the function's types: the first
+ entry is the full function type, the next ones are the type of
+ each arguments
+
+.. op:: OP_INLINED_CALL
+ Only used as an annotation to show that the instructions just above
+ correspond to a function that have been inlined.
+
+ * .func: (pseudo_t) the function (must be a symbol, alias .src))
+ * .arguments: list of pseudos that where the function's arguments
+ * .target: function return value (if any)
+ * .type: type of .target
+
+.. op:: OP_SLICE
+ Extract a "slice" from an aggregate.
+
+ * .base: (pseudo_t) aggregate (alias .src)
+ * .from, .len: offet & size of the "slice" within the aggregate
+ * .target: result
+ * .type: type of .target
+
+.. op:: OP_ASM
+ Inlined assembly code.
+
+ * .string: asm template
+ * .asm_rules: asm constraints, rules
+
+Sparse tagging (line numbers, context, whatever)
+------------------------------------------------
+.. op:: OP_CONTEXT
+ Currently only used for lock/unlock tracking.
+
+ * .context_expr: unused
+ * .increment: (1 for locking, -1 for unlocking)
+ * .check: (ignore the instruction if 0)
+
+Misc ops
+--------
+.. op:: OP_ENTRY
+ Function entry point (no associated semantic).
+
+.. op:: OP_BADOP
+ Invalid operation (should never be generated).
+
+.. op:: OP_NOP
+ No-op (should never be generated).
+
+.. op:: OP_DEATHNOTE
+ Annotation telling the pseudo will be death after the next
+ instruction (other than some other annotation, that is).
+
+.. # vim: tabstop=4
diff --git a/Documentation/conf.py b/Documentation/conf.py
index f7a68014..aae9d39b 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -29,6 +29,7 @@ needs_sphinx = '1.3'
sys.path.insert(0, os.path.abspath('sphinx'))
extensions = [
'cdoc'
+ , 'ir'
]
# support .md with python2 & python3
diff --git a/Documentation/doc-guide.rst b/Documentation/doc-guide.rst
index 80ec82c2..8133cb3a 100644
--- a/Documentation/doc-guide.rst
+++ b/Documentation/doc-guide.rst
@@ -149,3 +149,7 @@ will be displayed like this:
It's strongly encouraged to use this
function instead of open coding a simple
``++``.
+
+Intermediate Representation
+---------------------------
+.. c:autodoc:: Documentation/sphinx/ir.py
diff --git a/Documentation/index.rst b/Documentation/index.rst
index da006710..9825c8cd 100644
--- a/Documentation/index.rst
+++ b/Documentation/index.rst
@@ -20,8 +20,8 @@ Developer documentation
test-suite
dev-options
- IR
api
+ IR
doc-guide
How to contribute
diff --git a/Documentation/sphinx/ir.py b/Documentation/sphinx/ir.py
new file mode 100755
index 00000000..3028200a
--- /dev/null
+++ b/Documentation/sphinx/ir.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# SPDX_License-Identifier: MIT
+#
+# Copyright (C) 2018 Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
+#
+
+"""
+///
+// To document the instructions used in the intermediate representation
+// a new domain is defined: 'ir' with a directive::
+//
+// .. op: <OP_NAME>
+// <description of OP_NAME>
+// ...
+//
+// This is equivalent to using a definition list but with the name
+// also placed in the index (with 'IR instruction' as descriptions).
+
+"""
+
+import docutils
+import sphinx
+
+class IROpDirective(docutils.parsers.rst.Directive):
+
+ # use the first line of content as the argument, this allow
+ # to not have to write a blanck line after the directive
+ final_argument_whitespace = True
+ required_argument = 0
+ #optional_arguments = 0
+ has_content = True
+
+ objtype = None
+
+ def run(self):
+ self.env = self.state.document.settings.env
+
+ source = self.state.document
+ lineno = self.lineno
+ text = self.content
+ name = text[0]
+
+ node = docutils.nodes.section()
+ node['ids'].append(name)
+ node.document = source
+
+ index = '.. index:: pair: %s; IR instruction' % name
+ content = docutils.statemachine.ViewList()
+ content.append(index, source, lineno)
+ content.append('' , source, lineno)
+ content.append(name , source, lineno)
+ content.append('' , source, lineno)
+ self.state.nested_parse(content, self.content_offset, node)
+
+ defnode = docutils.nodes.definition()
+ self.state.nested_parse(text[1:], self.content_offset, defnode)
+ node.append(defnode)
+
+ return [node]
+
+class IRDomain(sphinx.domains.Domain):
+
+ """IR domain."""
+ name = 'ir'
+
+def setup(app):
+ app.add_domain(IRDomain)
+ app.add_directive_to_domain('ir', 'op', IROpDirective)
+
+ return {
+ 'version': '1.0',
+ 'parallel_read_safe': True,
+ }
+
+# vim: tabstop=4
diff --git a/builtin.c b/builtin.c
index b409a775..221c9899 100644
--- a/builtin.c
+++ b/builtin.c
@@ -82,7 +82,7 @@ error:
return 0;
}
-static int arguments_choose(struct expression *expr)
+static int args_triadic(struct expression *expr)
{
return eval_args(expr, 3);
}
@@ -195,8 +195,8 @@ static struct symbol_op expect_op = {
};
static struct symbol_op choose_op = {
+ .args = args_triadic,
.evaluate = evaluate_choose,
- .args = arguments_choose,
};
/* The argument is constant and valid if the cost is zero */
@@ -251,6 +251,71 @@ static struct symbol_op fp_unop_op = {
};
+static int evaluate_overflow_gen(struct expression *expr, int ptr)
+{
+ struct expression *arg;
+ int n = 0;
+
+ /* there will be exactly 3; we'd already verified that */
+ FOR_EACH_PTR(expr->args, arg) {
+ struct symbol *type;
+
+ n++;
+ if (!arg || !(type = arg->ctype))
+ return 0;
+ // 1st & 2nd args must be a basic integer type
+ // 3rd arg must be a pointer to such a type.
+ if (n == 3 && ptr) {
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ if (!type)
+ return 0;
+ if (type->type != SYM_PTR)
+ goto err;
+ type = type->ctype.base_type;
+ if (!type)
+ return 0;
+ }
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ if (!type)
+ return 0;
+ if (type->ctype.base_type != &int_type || type == &bool_ctype)
+ goto err;
+ } END_FOR_EACH_PTR(arg);
+
+ // the builtin returns a bool
+ expr->ctype = &bool_ctype;
+ return 1;
+
+err:
+ sparse_error(arg->pos, "invalid type for argument %d:", n);
+ info(arg->pos, " %s", show_typename(arg->ctype));
+ expr->ctype = &bad_ctype;
+ return 0;
+}
+
+static int evaluate_overflow(struct expression *expr)
+{
+ return evaluate_overflow_gen(expr, 1);
+}
+
+static struct symbol_op overflow_op = {
+ .args = args_triadic,
+ .evaluate = evaluate_overflow,
+};
+
+static int evaluate_overflow_p(struct expression *expr)
+{
+ return evaluate_overflow_gen(expr, 0);
+}
+
+static struct symbol_op overflow_p_op = {
+ .args = args_triadic,
+ .evaluate = evaluate_overflow_p,
+};
+
+
/*
* Builtin functions
*/
@@ -275,6 +340,12 @@ static struct sym_init {
{ "__builtin_isnan", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
{ "__builtin_isnormal", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
{ "__builtin_signbit", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
+ { "__builtin_add_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+ { "__builtin_sub_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+ { "__builtin_mul_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+ { "__builtin_add_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
+ { "__builtin_sub_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
+ { "__builtin_mul_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
{ NULL, NULL, 0 }
};
@@ -289,6 +360,7 @@ void init_builtins(int stream)
sym->ctype.base_type = ptr->base_type;
sym->ctype.modifiers = ptr->modifiers;
sym->op = ptr->op;
+ sym->builtin = 1;
}
}
@@ -302,6 +374,7 @@ static void declare_builtin(const char *name, struct symbol *rtype, int variadic
sym->ctype.base_type = fun;
sym->ctype.modifiers = MOD_TOPLEVEL;
+ sym->builtin = 1;
fun->ctype.base_type = rtype;
fun->variadic = variadic;
@@ -397,9 +470,18 @@ void declare_builtins(void)
declare_builtin("__builtin_realloc", &ptr_ctype, 0, &ptr_ctype, size_t_ctype, NULL);
declare_builtin("__builtin_return_address", &ptr_ctype, 0, &uint_ctype, NULL);
declare_builtin("__builtin_rindex", &string_ctype, 0, &const_string_ctype, &int_ctype, NULL);
+ declare_builtin("__builtin_sadd_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL);
+ declare_builtin("__builtin_saddl_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL);
+ declare_builtin("__builtin_saddll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL);
declare_builtin("__builtin_signbit", &int_ctype, 1, NULL);
+ declare_builtin("__builtin_smul_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL);
+ declare_builtin("__builtin_smull_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL);
+ declare_builtin("__builtin_smulll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL);
declare_builtin("__builtin_snprintf", &int_ctype, 1, &string_ctype, size_t_ctype, &const_string_ctype, NULL);
declare_builtin("__builtin_sprintf", &int_ctype, 1, &string_ctype, &const_string_ctype, NULL);
+ declare_builtin("__builtin_ssub_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL);
+ declare_builtin("__builtin_ssubl_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL);
+ declare_builtin("__builtin_ssubll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL);
declare_builtin("__builtin_stpcpy", &string_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
declare_builtin("__builtin_stpncpy", &string_ctype, 0, &const_string_ctype, &const_string_ctype, size_t_ctype, NULL);
declare_builtin("__builtin_strcasecmp", &int_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
@@ -422,7 +504,16 @@ void declare_builtins(void)
declare_builtin("__builtin_strspn", size_t_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
declare_builtin("__builtin_strstr", &string_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
declare_builtin("__builtin_trap", &void_ctype, 0, NULL);
+ declare_builtin("__builtin_uadd_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL);
+ declare_builtin("__builtin_uaddl_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL);
+ declare_builtin("__builtin_uaddll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL);
+ declare_builtin("__builtin_umul_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL);
+ declare_builtin("__builtin_umull_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL);
+ declare_builtin("__builtin_umulll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL);
declare_builtin("__builtin_unreachable", &void_ctype, 0, NULL);
+ declare_builtin("__builtin_usub_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL);
+ declare_builtin("__builtin_usubl_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL);
+ declare_builtin("__builtin_usubll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL);
declare_builtin("__builtin_va_arg_pack_len", size_t_ctype, 0, NULL);
declare_builtin("__builtin_vprintf", &int_ctype, 0, &const_string_ctype, va_list_ctype, NULL);
declare_builtin("__builtin_vsnprintf", &int_ctype, 0, &string_ctype, size_t_ctype, &const_string_ctype, va_list_ctype, NULL);
diff --git a/ident-list.h b/ident-list.h
index 5394f587..a37a4a1b 100644
--- a/ident-list.h
+++ b/ident-list.h
@@ -59,6 +59,7 @@ IDENT_RESERVED(__label__);
* sparse. */
IDENT(defined);
IDENT(once);
+IDENT(__has_builtin);
__IDENT(pragma_ident, "__pragma__", 0);
__IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0);
__IDENT(__func___ident, "__func__", 0);
diff --git a/lib.c b/lib.c
index 8bad856e..4692fe6d 100644
--- a/lib.c
+++ b/lib.c
@@ -1241,6 +1241,7 @@ static void create_builtin_stream(void)
add_pre_buffer("#add_system \"%s/include\"\n", gcc_base_dir);
add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir);
+ add_pre_buffer("#define __has_builtin(x) 0\n");
add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n");
diff --git a/pre-process.c b/pre-process.c
index e1550cdb..da4b7acd 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -146,13 +146,23 @@ static int token_defined(struct token *token)
return 0;
}
-static void replace_with_defined(struct token *token)
+static void replace_with_bool(struct token *token, bool val)
{
static const char *string[] = { "0", "1" };
- int defined = token_defined(token);
token_type(token) = TOKEN_NUMBER;
- token->number = string[defined];
+ token->number = string[val];
+}
+
+static void replace_with_defined(struct token *token)
+{
+ replace_with_bool(token, token_defined(token));
+}
+
+static void replace_with_has_builtin(struct token *token)
+{
+ struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL);
+ replace_with_bool(token, sym && sym->builtin);
}
static void expand_line(struct token *token)
@@ -1578,6 +1588,10 @@ static int expression_value(struct token **where)
state = 1;
beginning = list;
break;
+ } else if (p->ident == &__has_builtin_ident) {
+ state = 4;
+ beginning = list;
+ break;
}
if (!expand_one_symbol(list))
continue;
@@ -1608,6 +1622,33 @@ static int expression_value(struct token **where)
sparse_error(p->pos, "missing ')' after \"defined\"");
*list = p->next;
continue;
+
+ // __has_builtin(xyz)
+ case 4:
+ if (match_op(p, '(')) {
+ state = 5;
+ } else {
+ sparse_error(p->pos, "missing '(' after \"__has_builtin\"");
+ state = 0;
+ }
+ *beginning = p;
+ break;
+ case 5:
+ if (token_type(p) != TOKEN_IDENT) {
+ sparse_error(p->pos, "identifier expected");
+ state = 0;
+ break;
+ }
+ if (!match_op(p->next, ')'))
+ sparse_error(p->pos, "missing ')' after \"__has_builtin\"");
+ state = 6;
+ replace_with_has_builtin(p);
+ *beginning = p;
+ break;
+ case 6:
+ state = 0;
+ *list = p->next;
+ continue;
}
list = &p->next;
}
diff --git a/symbol.c b/symbol.c
index 4484eb5b..2dcabe85 100644
--- a/symbol.c
+++ b/symbol.c
@@ -697,6 +697,9 @@ struct symbol bool_ctype, void_ctype, type_ctype,
string_ctype, ptr_ctype, lazy_ptr_ctype,
incomplete_ctype, label_ctype, bad_ctype,
null_ctype;
+struct symbol int_ptr_ctype, uint_ptr_ctype;
+struct symbol long_ptr_ctype, ulong_ptr_ctype;
+struct symbol llong_ptr_ctype, ullong_ptr_ctype;
struct symbol float32_ctype, float32x_ctype;
struct symbol float64_ctype, float64x_ctype;
struct symbol float128_ctype;
@@ -779,6 +782,12 @@ static const struct ctype_declare {
{ &null_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &void_ctype },
{ &label_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &void_ctype },
{ &lazy_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &void_ctype },
+ { &int_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &int_ctype },
+ { &uint_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &uint_ctype },
+ { &long_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &long_ctype },
+ { &ulong_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &ulong_ctype },
+ { &llong_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &llong_ctype },
+ { &ullong_ptr_ctype,SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &ullong_ctype },
{ &const_void_ctype, SYM_NODE, MOD_CONST, NULL, NULL, &void_ctype },
{ &const_char_ctype, SYM_NODE, MOD_CONST, &bits_in_char, &max_int_alignment, &char_ctype },
diff --git a/symbol.h b/symbol.h
index c1ae4d2b..6d23503f 100644
--- a/symbol.h
+++ b/symbol.h
@@ -174,6 +174,7 @@ struct symbol {
designated_init:1,
forced_arg:1,
accessed:1,
+ builtin:1,
transparent_union:1;
struct expression *array_size;
struct ctype ctype;
@@ -268,6 +269,9 @@ extern struct symbol bool_ctype, void_ctype, type_ctype,
string_ctype, ptr_ctype, lazy_ptr_ctype,
incomplete_ctype, label_ctype, bad_ctype,
null_ctype;
+extern struct symbol int_ptr_ctype, uint_ptr_ctype;
+extern struct symbol long_ptr_ctype, ulong_ptr_ctype;
+extern struct symbol llong_ptr_ctype, ullong_ptr_ctype;
extern struct symbol float32_ctype, float32x_ctype;
extern struct symbol float64_ctype, float64x_ctype;
extern struct symbol float128_ctype;
diff --git a/validation/builtin-overflow.c b/validation/builtin-overflow.c
new file mode 100644
index 00000000..867eb42f
--- /dev/null
+++ b/validation/builtin-overflow.c
@@ -0,0 +1,246 @@
+enum e { OK };
+typedef _Bool bool;
+
+static int test(int i, long l, long long ll, enum e e, bool b, void *p)
+{
+ int rc = 0;
+
+ // should be OK
+ rc += __builtin_add_overflow(i, i, &i);
+ rc += __builtin_add_overflow(l, i, &i);
+ rc += __builtin_add_overflow(i, l, &i);
+ rc += __builtin_add_overflow(i, i, &l);
+ rc += __builtin_add_overflow(ll, i, &i);
+ rc += __builtin_add_overflow(i, ll, &i);
+ rc += __builtin_add_overflow(i, i, &ll);
+
+ rc += __builtin_add_overflow_p(i, i, i);
+ rc += __builtin_add_overflow_p(l, i, i);
+ rc += __builtin_add_overflow_p(i, l, i);
+ rc += __builtin_add_overflow_p(i, i, l);
+ rc += __builtin_add_overflow_p(ll, i, i);
+ rc += __builtin_add_overflow_p(i, ll, i);
+ rc += __builtin_add_overflow_p(i, i, ll);
+
+ rc += __builtin_sub_overflow(i, i, &i);
+ rc += __builtin_sub_overflow(l, i, &i);
+ rc += __builtin_sub_overflow(i, l, &i);
+ rc += __builtin_sub_overflow(i, i, &l);
+ rc += __builtin_sub_overflow(ll, i, &i);
+ rc += __builtin_sub_overflow(i, ll, &i);
+ rc += __builtin_sub_overflow(i, i, &ll);
+
+ rc += __builtin_sub_overflow_p(i, i, i);
+ rc += __builtin_sub_overflow_p(l, i, i);
+ rc += __builtin_sub_overflow_p(i, l, i);
+ rc += __builtin_sub_overflow_p(i, i, l);
+ rc += __builtin_sub_overflow_p(ll, i, i);
+ rc += __builtin_sub_overflow_p(i, ll, i);
+ rc += __builtin_sub_overflow_p(i, i, ll);
+
+ rc += __builtin_mul_overflow(i, i, &i);
+ rc += __builtin_mul_overflow(l, i, &i);
+ rc += __builtin_mul_overflow(i, l, &i);
+ rc += __builtin_mul_overflow(i, i, &l);
+ rc += __builtin_mul_overflow(ll, i, &i);
+ rc += __builtin_mul_overflow(i, ll, &i);
+ rc += __builtin_mul_overflow(i, i, &ll);
+
+ rc += __builtin_mul_overflow_p(i, i, i);
+ rc += __builtin_mul_overflow_p(l, i, i);
+ rc += __builtin_mul_overflow_p(i, l, i);
+ rc += __builtin_mul_overflow_p(i, i, l);
+ rc += __builtin_mul_overflow_p(ll, i, i);
+ rc += __builtin_mul_overflow_p(i, ll, i);
+ rc += __builtin_mul_overflow_p(i, i, ll);
+
+ // should be KO
+ rc += __builtin_add_overflow();
+ rc += __builtin_add_overflow(i);
+ rc += __builtin_add_overflow(i, i);
+ rc += __builtin_add_overflow(i, i, &i, i);
+ rc += __builtin_add_overflow(e, i, &i);
+ rc += __builtin_add_overflow(i, e, &i);
+ rc += __builtin_add_overflow(i, i, &e);
+ rc += __builtin_add_overflow(b, i, &i);
+ rc += __builtin_add_overflow(i, b, &i);
+ rc += __builtin_add_overflow(i, i, &b);
+ rc += __builtin_add_overflow(i, i, p);
+
+ rc += __builtin_add_overflow_p();
+ rc += __builtin_add_overflow_p(i);
+ rc += __builtin_add_overflow_p(i, i);
+ rc += __builtin_add_overflow_p(i, i, i, i);
+ rc += __builtin_add_overflow_p(e, i, i);
+ rc += __builtin_add_overflow_p(i, e, i);
+ rc += __builtin_add_overflow_p(i, i, e);
+ rc += __builtin_add_overflow_p(b, i, i);
+ rc += __builtin_add_overflow_p(i, b, i);
+ rc += __builtin_add_overflow_p(i, i, b);
+ rc += __builtin_add_overflow_p(i, i, p);
+
+ rc += __builtin_sub_overflow();
+ rc += __builtin_sub_overflow(i);
+ rc += __builtin_sub_overflow(i, i);
+ rc += __builtin_sub_overflow(i, i, &i, i);
+ rc += __builtin_sub_overflow(e, i, &i);
+ rc += __builtin_sub_overflow(i, e, &i);
+ rc += __builtin_sub_overflow(i, i, &e);
+ rc += __builtin_sub_overflow(b, i, &i);
+ rc += __builtin_sub_overflow(i, b, &i);
+ rc += __builtin_sub_overflow(i, i, &b);
+ rc += __builtin_sub_overflow(i, i, p);
+
+ rc += __builtin_sub_overflow_p();
+ rc += __builtin_sub_overflow_p(i);
+ rc += __builtin_sub_overflow_p(i, i);
+ rc += __builtin_sub_overflow_p(i, i, i, i);
+ rc += __builtin_sub_overflow_p(e, i, i);
+ rc += __builtin_sub_overflow_p(i, e, i);
+ rc += __builtin_sub_overflow_p(i, i, e);
+ rc += __builtin_sub_overflow_p(b, i, i);
+ rc += __builtin_sub_overflow_p(i, b, i);
+ rc += __builtin_sub_overflow_p(i, i, b);
+ rc += __builtin_sub_overflow_p(i, i, p);
+
+ rc += __builtin_mul_overflow();
+ rc += __builtin_mul_overflow(i);
+ rc += __builtin_mul_overflow(i, i);
+ rc += __builtin_mul_overflow(i, i, &i, i);
+ rc += __builtin_mul_overflow(e, i, &i);
+ rc += __builtin_mul_overflow(i, e, &i);
+ rc += __builtin_mul_overflow(i, i, &e);
+ rc += __builtin_mul_overflow(b, i, &i);
+ rc += __builtin_mul_overflow(i, b, &i);
+ rc += __builtin_mul_overflow(i, i, &b);
+ rc += __builtin_mul_overflow(i, i, p);
+
+ rc += __builtin_mul_overflow_p();
+ rc += __builtin_mul_overflow_p(i);
+ rc += __builtin_mul_overflow_p(i, i);
+ rc += __builtin_mul_overflow_p(i, i, i, i);
+ rc += __builtin_mul_overflow_p(e, i, i);
+ rc += __builtin_mul_overflow_p(i, e, i);
+ rc += __builtin_mul_overflow_p(i, i, e);
+ rc += __builtin_mul_overflow_p(b, i, i);
+ rc += __builtin_mul_overflow_p(i, b, i);
+ rc += __builtin_mul_overflow_p(i, i, b);
+ rc += __builtin_mul_overflow_p(i, i, p);
+
+ return rc;
+}
+
+/*
+ * check-name: builtin-overflow
+ *
+ * check-error-start
+builtin-overflow.c:58:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:59:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:60:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:61:37: error: too many arguments for __builtin_add_overflow
+builtin-overflow.c:62:38: error: invalid type for argument 1:
+builtin-overflow.c:62:38: int enum e [signed] e
+builtin-overflow.c:63:41: error: invalid type for argument 2:
+builtin-overflow.c:63:41: int enum e [signed] e
+builtin-overflow.c:64:45: error: invalid type for argument 3:
+builtin-overflow.c:64:45: int enum e *<noident>
+builtin-overflow.c:65:38: error: invalid type for argument 1:
+builtin-overflow.c:65:38: bool [unsigned] [usertype] b
+builtin-overflow.c:66:41: error: invalid type for argument 2:
+builtin-overflow.c:66:41: bool [unsigned] [usertype] b
+builtin-overflow.c:67:45: error: invalid type for argument 3:
+builtin-overflow.c:67:45: bool *<noident>
+builtin-overflow.c:68:44: error: invalid type for argument 3:
+builtin-overflow.c:68:44: void *p
+builtin-overflow.c:70:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:71:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:72:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:73:39: error: too many arguments for __builtin_add_overflow_p
+builtin-overflow.c:74:40: error: invalid type for argument 1:
+builtin-overflow.c:74:40: int enum e [signed] [addressable] e
+builtin-overflow.c:75:43: error: invalid type for argument 2:
+builtin-overflow.c:75:43: int enum e [signed] [addressable] e
+builtin-overflow.c:76:46: error: invalid type for argument 3:
+builtin-overflow.c:76:46: int enum e [signed] [addressable] e
+builtin-overflow.c:77:40: error: invalid type for argument 1:
+builtin-overflow.c:77:40: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:78:43: error: invalid type for argument 2:
+builtin-overflow.c:78:43: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:79:46: error: invalid type for argument 3:
+builtin-overflow.c:79:46: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:80:46: error: invalid type for argument 3:
+builtin-overflow.c:80:46: void *p
+builtin-overflow.c:82:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:83:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:84:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:85:37: error: too many arguments for __builtin_sub_overflow
+builtin-overflow.c:86:38: error: invalid type for argument 1:
+builtin-overflow.c:86:38: int enum e [signed] [addressable] e
+builtin-overflow.c:87:41: error: invalid type for argument 2:
+builtin-overflow.c:87:41: int enum e [signed] [addressable] e
+builtin-overflow.c:88:45: error: invalid type for argument 3:
+builtin-overflow.c:88:45: int enum e *<noident>
+builtin-overflow.c:89:38: error: invalid type for argument 1:
+builtin-overflow.c:89:38: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:90:41: error: invalid type for argument 2:
+builtin-overflow.c:90:41: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:91:45: error: invalid type for argument 3:
+builtin-overflow.c:91:45: bool *<noident>
+builtin-overflow.c:92:44: error: invalid type for argument 3:
+builtin-overflow.c:92:44: void *p
+builtin-overflow.c:94:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:95:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:96:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:97:39: error: too many arguments for __builtin_sub_overflow_p
+builtin-overflow.c:98:40: error: invalid type for argument 1:
+builtin-overflow.c:98:40: int enum e [signed] [addressable] e
+builtin-overflow.c:99:43: error: invalid type for argument 2:
+builtin-overflow.c:99:43: int enum e [signed] [addressable] e
+builtin-overflow.c:100:46: error: invalid type for argument 3:
+builtin-overflow.c:100:46: int enum e [signed] [addressable] e
+builtin-overflow.c:101:40: error: invalid type for argument 1:
+builtin-overflow.c:101:40: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:102:43: error: invalid type for argument 2:
+builtin-overflow.c:102:43: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:103:46: error: invalid type for argument 3:
+builtin-overflow.c:103:46: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:104:46: error: invalid type for argument 3:
+builtin-overflow.c:104:46: void *p
+builtin-overflow.c:106:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:107:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:108:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:109:37: error: too many arguments for __builtin_mul_overflow
+builtin-overflow.c:110:38: error: invalid type for argument 1:
+builtin-overflow.c:110:38: int enum e [signed] [addressable] e
+builtin-overflow.c:111:41: error: invalid type for argument 2:
+builtin-overflow.c:111:41: int enum e [signed] [addressable] e
+builtin-overflow.c:112:45: error: invalid type for argument 3:
+builtin-overflow.c:112:45: int enum e *<noident>
+builtin-overflow.c:113:38: error: invalid type for argument 1:
+builtin-overflow.c:113:38: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:114:41: error: invalid type for argument 2:
+builtin-overflow.c:114:41: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:115:45: error: invalid type for argument 3:
+builtin-overflow.c:115:45: bool *<noident>
+builtin-overflow.c:116:44: error: invalid type for argument 3:
+builtin-overflow.c:116:44: void *p
+builtin-overflow.c:118:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:119:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:120:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:121:39: error: too many arguments for __builtin_mul_overflow_p
+builtin-overflow.c:122:40: error: invalid type for argument 1:
+builtin-overflow.c:122:40: int enum e [signed] [addressable] e
+builtin-overflow.c:123:43: error: invalid type for argument 2:
+builtin-overflow.c:123:43: int enum e [signed] [addressable] e
+builtin-overflow.c:124:46: error: invalid type for argument 3:
+builtin-overflow.c:124:46: int enum e [signed] [addressable] e
+builtin-overflow.c:125:40: error: invalid type for argument 1:
+builtin-overflow.c:125:40: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:126:43: error: invalid type for argument 2:
+builtin-overflow.c:126:43: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:127:46: error: invalid type for argument 3:
+builtin-overflow.c:127:46: bool [unsigned] [addressable] [usertype] b
+builtin-overflow.c:128:46: error: invalid type for argument 3:
+builtin-overflow.c:128:46: void *p
+ * check-error-end
+ */
diff --git a/validation/preprocessor/has-builtin.c b/validation/preprocessor/has-builtin.c
new file mode 100644
index 00000000..03272fc9
--- /dev/null
+++ b/validation/preprocessor/has-builtin.c
@@ -0,0 +1,43 @@
+#ifndef __has_builtin
+__has_builtin()??? Quesako?
+#define __has_builtin(x) 0
+#else
+"has __has_builtin(), yeah!"
+#endif
+
+#if __has_builtin(nothing)
+#error "not a builtin!"
+#endif
+
+#if __has_builtin(__builtin_offsetof) \
+ || __has_builtin(__builtin_types_compatible_p)
+#error "builtin ops are not builtin functions!"
+#endif
+
+#if __has_builtin(__builtin_va_list) \
+ || __has_builtin(__builtin_ms_va_list)
+#error "builtin types are not builtin functions!"
+#endif
+
+#if __has_builtin(__builtin_abs)
+abs
+#endif
+
+#if __has_builtin(__builtin_constant_p)
+constant_p
+#endif
+
+123 __has_builtin(abc) def
+
+/*
+ * check-name: has-builtin
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"has __has_builtin(), yeah!"
+abs
+constant_p
+123 0 def
+ * check-output-end
+ */