summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt14
-rw-r--r--src/core/cpu/builtins.cpp11
-rw-r--r--src/runtime/CMakeLists.txt70
-rw-r--r--src/runtime/builtins.def18
-rwxr-xr-xsrc/runtime/builtins.py365
-rwxr-xr-xsrc/runtime/embed.py40
-rw-r--r--src/runtime/stdlib.c5
-rw-r--r--tests/test_builtins.cpp36
8 files changed, 523 insertions, 36 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 348d4bc..14927bf 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -45,6 +45,10 @@ set(COAL_SRC_FILES
${CMAKE_CURRENT_BINARY_DIR}/runtime/stdlib.h.embed.h
${CMAKE_CURRENT_BINARY_DIR}/runtime/stdlib.c.bc.embed.h
+ ${CMAKE_CURRENT_BINARY_DIR}/runtime/builtins_impl.h
+ ${CMAKE_CURRENT_BINARY_DIR}/runtime/builtins_def.h
+ ${CMAKE_CURRENT_BINARY_DIR}/runtime/stdlib_impl.h
+ ${CMAKE_CURRENT_BINARY_DIR}/runtime/stdlib_def.h
)
add_subdirectory(runtime)
@@ -55,8 +59,18 @@ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/runtime/stdlib.h.embed.h
PROPERTIES GENERATED 1)
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/runtime/stdlib.c.bc.embed.h
PROPERTIES GENERATED 1)
+set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/runtime/builtins_impl.h
+ PROPERTIES GENERATED 1)
+set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/runtime/builtins_def.h
+ PROPERTIES GENERATED 1)
+set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/runtime/stdlib_impl.h
+ PROPERTIES GENERATED 1)
+set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/runtime/stdlib_def.h
+ PROPERTIES GENERATED 1)
+
add_dependencies(OpenCL generate_stdlib_h)
add_dependencies(OpenCL generate_stdlib_c)
+add_dependencies(OpenCL generate_builtins)
SET(LIBRARY_OUTPUT_PATH ${Coal_BINARY_DIR}/lib)
diff --git a/src/core/cpu/builtins.cpp b/src/core/cpu/builtins.cpp
index 98a6e65..1993e10 100644
--- a/src/core/cpu/builtins.cpp
+++ b/src/core/cpu/builtins.cpp
@@ -47,8 +47,10 @@
#include <signal.h>
#include <llvm/Function.h>
+
#include <iostream>
#include <cstring>
+#include <cmath>
#include <stdio.h>
@@ -396,6 +398,12 @@ static void read_imageuif(uint32_t *result, Image2D *image, float x, float y,
}
/*
+ * Built-in functions generated by src/runtime/builtins.py
+ */
+
+#include <runtime/builtins_impl.h>
+
+/*
* Bridge between LLVM and us
*/
static void unimplemented_stub()
@@ -456,6 +464,9 @@ void *getBuiltin(const std::string &name)
else if (name == "__cpu_read_imageuif")
return (void *)&read_imageuif;
+ // Built-in functions generated by src/runtime/builtins.py
+#include <runtime/builtins_def.h>
+
else if (name == "debug")
return (void *)&printf;
diff --git a/src/runtime/CMakeLists.txt b/src/runtime/CMakeLists.txt
index e381ebf..f825825 100644
--- a/src/runtime/CMakeLists.txt
+++ b/src/runtime/CMakeLists.txt
@@ -1,35 +1,45 @@
-macro(EMBED_FILE INFILE INNAME)
- add_custom_command(
- OUTPUT ${INFILE}.embed.h
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/embed.py
- ${CMAKE_CURRENT_SOURCE_DIR}/${INFILE}
- ${CMAKE_CURRENT_BINARY_DIR}/${INFILE}.embed.h
- DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/embed.py
- ${CMAKE_CURRENT_SOURCE_DIR}/${INFILE})
+add_custom_command(
+ OUTPUT stdlib.h.embed.h
+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/embed.py
+ ${CMAKE_CURRENT_BINARY_DIR}/stdlib.h.embed.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/stdlib.h
+ ${CMAKE_CURRENT_BINARY_DIR}/stdlib_def.h
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/embed.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/stdlib.h
+ ${CMAKE_CURRENT_BINARY_DIR}/stdlib_def.h)
- add_custom_target(generate_${INNAME} DEPENDS
- ${CMAKE_CURRENT_BINARY_DIR}/${INFILE}.embed.h)
-endmacro(EMBED_FILE)
+add_custom_target(generate_stdlib_h DEPENDS
+ ${CMAKE_CURRENT_BINARY_DIR}/stdlib.h.embed.h)
-macro(COMPILE_BITCODE INFILE INNAME)
- add_custom_command(
- OUTPUT ${INFILE}.bc
- COMMAND clang -c -emit-llvm -x cl -O2
- ${CMAKE_CURRENT_SOURCE_DIR}/${INFILE}
- -o ${CMAKE_CURRENT_BINARY_DIR}/${INFILE}.bc
- DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${INFILE})
+add_custom_command(
+ OUTPUT stdlib.c.bc
+ COMMAND clang -c -emit-llvm -x cl -O2 -nobuiltininc -nostdinc -fno-builtin
+ ${CMAKE_CURRENT_SOURCE_DIR}/stdlib.c
+ -I${CMAKE_CURRENT_BINARY_DIR}
+ -o ${CMAKE_CURRENT_BINARY_DIR}/stdlib.c.bc
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/stdlib.c)
- add_custom_command(
- OUTPUT ${INFILE}.bc.embed.h
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/embed.py
- ${CMAKE_CURRENT_BINARY_DIR}/${INFILE}.bc
- ${CMAKE_CURRENT_BINARY_DIR}/${INFILE}.bc.embed.h
- DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/embed.py
- ${CMAKE_CURRENT_BINARY_DIR}/${INFILE}.bc)
+add_custom_command(
+ OUTPUT stdlib.c.bc.embed.h
+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/embed.py
+ ${CMAKE_CURRENT_BINARY_DIR}/stdlib.c.bc.embed.h
+ ${CMAKE_CURRENT_BINARY_DIR}/stdlib.c.bc
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/embed.py
+ ${CMAKE_CURRENT_BINARY_DIR}/stdlib.c.bc)
- add_custom_target(generate_${INNAME} DEPENDS
- ${CMAKE_CURRENT_BINARY_DIR}/${INFILE}.bc.embed.h)
-endmacro(COMPILE_BITCODE)
+add_custom_target(generate_stdlib_c DEPENDS
+ ${CMAKE_CURRENT_BINARY_DIR}/stdlib.c.bc.embed.h)
-EMBED_FILE(stdlib.h stdlib_h)
-COMPILE_BITCODE(stdlib.c stdlib_c)
+add_custom_command(
+ OUTPUT builtins_def.h stdlib_def.h builtins_impl.h stdlib_impl.h
+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/builtins.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/builtins.def
+ ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/builtins.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/builtins.def)
+
+add_custom_target(generate_builtins DEPENDS
+ ${CMAKE_CURRENT_BINARY_DIR}/builtins_def.h
+ ${CMAKE_CURRENT_BINARY_DIR}/builtins_impl.h
+ ${CMAKE_CURRENT_BINARY_DIR}/stdlib_def.h
+ ${CMAKE_CURRENT_BINARY_DIR}/stdlib_impl.h)
diff --git a/src/runtime/builtins.def b/src/runtime/builtins.def
new file mode 100644
index 0000000..39e705b
--- /dev/null
+++ b/src/runtime/builtins.def
@@ -0,0 +1,18 @@
+def vecf : float2 float3 float4 float8 float16
+def veci : int2 int3 int4 int8 int16
+
+def vec : $vecf $veci
+def gentype : float $vecf
+
+func $type fmin $gentype : x:$type y:$type
+ return (x < y ? x : y);
+end
+
+native float cos float : x:float
+ return std::cos(x);
+end
+
+native $type cos $vecf : x:$type
+ for (unsigned int i=0; i<$vecdim; ++i)
+ result[i] = std::cos(x[i]);
+end
diff --git a/src/runtime/builtins.py b/src/runtime/builtins.py
new file mode 100755
index 0000000..b38f7d1
--- /dev/null
+++ b/src/runtime/builtins.py
@@ -0,0 +1,365 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2011, Denis Steckelmacher <steckdenis@yahoo.fr>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the copyright holder nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+# builtins.py <def> <outdir>
+
+import sys
+
+class Function:
+ class Arg:
+ def __init__(self, name, t):
+ self.name = name
+ self.t = t
+
+ KIND_BUILTINS_IMPL = 0 # static function in builtins.cpp
+ KIND_BUILTINS_DEF = 1 # if (name == '__cpu_$name') return (void *)&name;
+ KIND_STDLIB_IMPL = 2 # OpenCL C function in stdlib.c
+ KIND_STDLIB_DEF = 3 # Header in stdlib.h
+ KIND_STDLIB_STUB = 4 # OpenCL C stub in stdlib.c: calls __cpu_$name
+ KIND_STDLIB_STUB_DEF = 5 # __cpu_$name declared in stdlib.c
+
+ def __init__(self, name, native):
+ self.name = name
+ self.native = native
+
+ self.args = [] # Array <Arg>
+ self.types = [] # Array <str>
+ self.return_type = ''
+ self.body = ''
+
+ def set_return_type(self, ty):
+ self.return_type = ty
+
+ def append_body(self, body):
+ self.body += body
+
+ def add_arg(self, name, ty):
+ self.args.append(self.Arg(name, ty))
+
+ def add_type(self, ty):
+ self.types.append(ty)
+
+ def mangled_name(self, current_type):
+ return_type = self.return_type
+ if return_type == '$type':
+ return_type = current_type
+
+ rs = return_type + '_' + self.name
+ first = True
+
+ for a in self.args:
+ if first:
+ rs += '_'
+ first = False
+
+ arg_type = a.t
+ if arg_type == '$type':
+ arg_type = current_type
+ rs += arg_type
+
+ return rs
+
+ def arg_list(self, current_type, handle_first_arg):
+ rs = ''
+ first = True
+ append_arg = None
+
+ # We may need a first "result" arg
+ if handle_first_arg:
+ return_type = self.return_type
+ if return_type == '$type':
+ return_type = current_type
+
+ if return_type[-1].isdigit():
+ # Return is a vector
+ append_arg = self.Arg('result', return_type)
+
+ if append_arg:
+ args = [append_arg]
+ args.extend(self.args)
+ else:
+ args = self.args
+
+ for arg in args:
+ # Resolve type
+ arg_type = arg.t
+ if arg_type == '$type':
+ arg_type = current_type
+
+ # We need to pass vector arguments as pointers
+ arg_vector = False
+ if handle_first_arg:
+ arg_vector = arg_type[-1].isdigit()
+ arg_type = arg_type.rstrip('0123456789')
+
+ # Build the string
+ if not first:
+ rs += ', '
+ first = False
+
+ rs += arg_type + ' '
+
+ if arg_vector:
+ rs += '*'
+
+ rs += arg.name
+
+ return rs
+
+ def write(self, current_type, kind):
+ # Template:
+ # (static) $ret_type $name($args) {
+ # $body
+ # }
+ rs = ''
+
+ if kind == self.KIND_BUILTINS_IMPL:
+ rs = 'static '
+ elif kind == self.KIND_BUILTINS_DEF:
+ rs += ' else if (name == "__cpu_' + self.mangled_name(current_type) + '")\n'
+ rs += ' return (void *)&' + self.mangled_name(current_type) + ';\n'
+ return rs
+
+ # Calculate return type
+ return_type = self.return_type
+ if return_type == '$type':
+ return_type = current_type
+
+ if (kind == self.KIND_BUILTINS_IMPL or kind == self.KIND_STDLIB_STUB_DEF) \
+ and return_type[-1].isdigit():
+ return_type = 'void' # We'll use a 'result' argument
+
+ rs += return_type + ' '
+
+ # Append mangled name if needed
+ if kind == self.KIND_BUILTINS_IMPL:
+ rs += self.mangled_name(current_type)
+ elif kind == self.KIND_STDLIB_STUB_DEF:
+ rs += '__cpu_' + self.mangled_name(current_type)
+ else:
+ # No need to mangle the name, but add OVERLOAD
+ rs += 'OVERLOAD ' + self.name
+
+ # Print function args
+ rs += '('
+ rs += self.arg_list(current_type, kind == self.KIND_BUILTINS_IMPL or \
+ kind == self.KIND_STDLIB_STUB_DEF)
+ rs += ')'
+
+ # If only a declaration, end it
+ if kind == self.KIND_STDLIB_DEF or kind == self.KIND_STDLIB_STUB_DEF:
+ rs += ';\n'
+ return rs
+
+ # Add the body
+ rs += '\n{\n'
+
+ if kind == self.KIND_STDLIB_STUB:
+ # Special body : call __cpu_$name
+ return_is_vector = return_type[-1].isdigit()
+ if return_is_vector:
+ # Need to create a temporary
+ rs += ' ' + return_type + ' result;\n'
+ rs += '\n'
+
+ # Call the cpu stub
+ rs += ' '
+ if not return_is_vector:
+ rs += 'return '
+
+ rs += '__cpu_' + self.mangled_name(current_type) + '('
+
+ # Pass the result if needed
+ first = True
+ if return_is_vector:
+ rs += '(' + return_type.rstrip('0123456789') + ' *)&result'
+ first = False
+
+ # Append the args
+ for arg in self.args:
+ # Resolve type
+ arg_type = arg.t
+ if arg_type == '$type':
+ arg_type = current_type
+ arg_vector = arg_type[-1].isdigit()
+
+ if not first:
+ rs += ', '
+ first = False
+
+ # We need to pass vector arguments as pointers
+ if arg_vector:
+ rs += '(' + arg_type.rstrip('0123456789') + ' *)&' + arg.name
+ else:
+ rs += arg.name
+
+ # End the call
+ rs += ');\n'
+
+ if return_is_vector:
+ rs += '\n return result;\n'
+
+ rs += '}\n\n'
+ else:
+ # Simply copy the body
+ vecdim = '1'
+
+ if current_type[-1].isdigit():
+ if current_type[-2].isdigit():
+ vecdim = current_type[-2:]
+ else:
+ vecdim = current_type[-1]
+
+ rs += self.body.replace('$type', current_type) \
+ .replace('$vecdim', vecdim)
+ rs += '\n}\n\n'
+
+ return rs
+
+class Generator:
+ builtins_impl_file = 'builtins_impl.h' # static functions
+ builtins_def_file = 'builtins_def.h' # if () in getBuiltin
+ stdlib_impl_file = 'stdlib_impl.h' # stdlib.c functions
+ stdlib_def_file = 'stdlib_def.h' # stdlib.h definitions
+
+ def __init__(self, out_path):
+ self.out_path = out_path
+
+ # Buffers
+ self.builtins_impl_buffer = ''
+ self.builtins_def_buffer = ''
+ self.stdlib_impl_buffer = ''
+ self.stdlib_def_buffer = ''
+
+ def add_function(self, function):
+ for t in function.types:
+ if function.native:
+ self.stdlib_impl_buffer += function.write(t, function.KIND_STDLIB_STUB_DEF)
+ self.stdlib_impl_buffer += function.write(t, function.KIND_STDLIB_STUB)
+ self.stdlib_def_buffer += function.write(t, function.KIND_STDLIB_DEF)
+ self.builtins_impl_buffer += function.write(t, function.KIND_BUILTINS_IMPL)
+ self.builtins_def_buffer += function.write(t, function.KIND_BUILTINS_DEF)
+ else:
+ self.stdlib_def_buffer += function.write(t, function.KIND_STDLIB_DEF)
+ self.stdlib_impl_buffer += function.write(t, function.KIND_STDLIB_IMPL)
+
+ def write(self):
+ of = open(self.out_path + '/' + self.stdlib_def_file, 'w')
+ of.write(self.stdlib_def_buffer)
+ of.close()
+
+ of = open(self.out_path + '/' + self.stdlib_impl_file, 'w')
+ of.write(self.stdlib_impl_buffer)
+ of.close()
+
+ of = open(self.out_path + '/' + self.builtins_def_file, 'w')
+ of.write(self.builtins_def_buffer)
+ of.close()
+
+ of = open(self.out_path + '/' + self.builtins_impl_file, 'w')
+ of.write(self.builtins_impl_buffer)
+ of.close()
+
+class Parser:
+ def __init__(self, generator, def_file_name):
+ self.generator = generator
+ self.def_file_name = def_file_name
+
+ self.defs = {}
+
+ def replace_variable(self, token):
+ result = []
+
+ if token[0] == '$':
+ for tok in self.defs[token[1:]]:
+ result.extend(self.replace_variable(tok))
+ else:
+ result.append(token)
+
+ return result
+
+ def parse(self):
+ def_file = open(self.def_file_name, 'rb')
+ current_function = None
+
+ for line in def_file:
+ if current_function:
+ # End if we encounter an end
+ if line.startswith('end'):
+ self.generator.add_function(current_function)
+ current_function = None
+ else:
+ # Add a line to the body
+ current_function.append_body(line)
+ else:
+ line = line.strip()
+ tokens = line.split(' ')
+ tok = tokens[0]
+
+ if tok == 'def':
+ # A definition : def <variable> : [values]
+ name = tokens[1]
+ values = []
+
+ for token in tokens[3:]:
+ values.extend(self.replace_variable(token))
+
+ self.defs[name] = values
+ elif tok == 'func' or tok == 'native':
+ # Function : func|native <ret_type> <name> [types] : [args]
+ current_function = Function(tokens[2], \
+ tokens[0] == 'native')
+
+ current_function.set_return_type(tokens[1])
+
+ # Explore the types and args
+ in_types = True
+
+ for token in tokens[3:]:
+ if token == ':':
+ in_types = False
+ elif in_types:
+ for ty in self.replace_variable(token):
+ current_function.add_type(ty)
+ else:
+ # Parameters
+ parts = token.split(':')
+ current_function.add_arg(parts[0], parts[1])
+
+ def_file.close()
+
+if __name__ == '__main__':
+ def_file = sys.argv[1]
+ out_dir = sys.argv[2]
+
+ gen = Generator(out_dir)
+ parser = Parser(gen, def_file)
+
+ parser.parse()
+ gen.write()
diff --git a/src/runtime/embed.py b/src/runtime/embed.py
index 81a4462..7d40cbb 100755
--- a/src/runtime/embed.py
+++ b/src/runtime/embed.py
@@ -1,16 +1,44 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2011, Denis Steckelmacher <steckdenis@yahoo.fr>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the copyright holder nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# embed.py <filename> <outfile>
-# <filename> => <outfile>
+# embed.py <outfile> <filenames..>
+# <filenames> => <outfile>
import sys
-infile = open(sys.argv[1], 'rb')
-name = sys.argv[1].split('/')[-1].replace('.', '_')
-outfile = open(sys.argv[2], 'w')
+outfile = open(sys.argv[1], 'w')
+name = sys.argv[1].split('/')[-1].replace('.embed.h', '').replace('.', '_')
-data = infile.read()
+data = ''
+
+for i in xrange(len(sys.argv) - 1):
+ infile = open(sys.argv[i + 1], 'rb')
+ data += infile.read()
# Header
outfile.write('#ifndef __%s__\n' % name.upper())
diff --git a/src/runtime/stdlib.c b/src/runtime/stdlib.c
index 0f10f0d..c2bb2eb 100644
--- a/src/runtime/stdlib.c
+++ b/src/runtime/stdlib.c
@@ -267,3 +267,8 @@ int OVERLOAD get_image_channel_order(image3d_t image)
return __cpu_get_image_channel_order(image);
}
+/*
+ * Built-in functions generated by src/runtime/builtins.py
+ */
+
+#include <stdlib_impl.h>
diff --git a/tests/test_builtins.cpp b/tests/test_builtins.cpp
index 94e836e..d8a5826 100644
--- a/tests/test_builtins.cpp
+++ b/tests/test_builtins.cpp
@@ -95,6 +95,17 @@ const char image_source[] =
" fcolor = read_imagef(image3, sampler, fcoords);\n"
"}\n";
+const char builtins_source[] =
+ "__kernel void test_case(__global uint *rs) {\n"
+ " float2 f2;\n"
+ "\n"
+ " f2.x = 1.0f;\n"
+ " f2.y = 0.0f;\n"
+ "\n"
+ " if (cos(f2).y != 1.0f) { *rs = 1; return; }\n"
+ " if (cos(0.0f) != 1.0f) { *rs = 2; return; }\n"
+ "}\n";
+
enum TestCaseKind
{
NormalKind,
@@ -357,6 +368,30 @@ START_TEST (test_image)
}
END_TEST
+START_TEST (test_builtins)
+{
+ uint32_t rs = run_kernel(builtins_source, NormalKind);
+ const char *errstr = 0;
+
+ switch (rs)
+ {
+ case 1:
+ errstr = "float2 cos(float2) doesn't behave correctly";
+ break;
+ case 2:
+ errstr = "float cos(float) doesn't behave correctly";
+ break;
+ default:
+ errstr = default_error(rs);
+ }
+
+ fail_if(
+ errstr != 0,
+ errstr
+ );
+}
+END_TEST
+
TCase *cl_builtins_tcase_create(void)
{
TCase *tc = NULL;
@@ -364,5 +399,6 @@ TCase *cl_builtins_tcase_create(void)
tcase_add_test(tc, test_sampler);
tcase_add_test(tc, test_barrier);
tcase_add_test(tc, test_image);
+ tcase_add_test(tc, test_builtins);
return tc;
}