brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.8 KiB · 737ab9d Raw
551 lines · python
1##===----------------------------------------------------------------------===##2#3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4# See https://llvm.org/LICENSE.txt for license information.5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6#7##===----------------------------------------------------------------------===##8#9# This script generates OpenCL type conversion builtins, which are all of the10# OpenCL functions in the form:11#12#   <prefix>convert_<destTypen><_sat><_roundingMode>(<sourceTypen>)13#14# The internal "CLC" versions of these builtins, with the <prefix> '__clc_'15# contain the actual implementations. These are generated by passing the16# '--clc' flag to the script.17#18# The OpenCL builtins, without any prefix, forward on to the CLC versions.19#20##===----------------------------------------------------------------------===##21 22import argparse23from sys import stderr24from os import path25 26parser = argparse.ArgumentParser()27parser.add_argument(28    "--clc", action="store_true", help="Generate clc internal conversions"29)30parser.add_argument(31    "--clspv", action="store_true", help="Generate the clspv variant of the code"32)33args = parser.parse_args()34 35clc = args.clc36clspv = args.clspv37 38 39# We don't generate clspv-specific code for clc conversions - don't allow this40# accidentally (later checks rely on mutual exclusivity)41if clc and clspv:42    print("Error: clc and clspv conversions are mutually exclusive", file=stderr)43    exit(1)44 45 46types = [47    "char",48    "uchar",49    "short",50    "ushort",51    "int",52    "uint",53    "long",54    "ulong",55    "half",56    "float",57    "double",58]59int_types = ["char", "uchar", "short", "ushort", "int", "uint", "long", "ulong"]60unsigned_types = ["uchar", "ushort", "uint", "ulong"]61float_types = ["half", "float", "double"]62int64_types = ["long", "ulong"]63float64_types = ["double"]64float16_types = ["half"]65vector_sizes = ["", "2", "3", "4", "8", "16"]66half_sizes = [("2", ""), ("4", "2"), ("8", "4"), ("16", "8")]67 68saturation = ["", "_sat"]69rounding_modes = ["_rtz", "_rte", "_rtp", "_rtn"]70 71bool_type = {72    "char": "char",73    "uchar": "char",74    "short": "short",75    "ushort": "short",76    "int": "int",77    "uint": "int",78    "long": "long",79    "ulong": "long",80    "half": "short",81    "float": "int",82    "double": "long",83}84 85unsigned_type = {86    "char": "uchar",87    "uchar": "uchar",88    "short": "ushort",89    "ushort": "ushort",90    "int": "uint",91    "uint": "uint",92    "long": "ulong",93    "ulong": "ulong",94}95 96sizeof_type = {97    "char": 1,98    "uchar": 1,99    "short": 2,100    "ushort": 2,101    "int": 4,102    "uint": 4,103    "long": 8,104    "ulong": 8,105    "half": 2,106    "float": 4,107    "double": 8,108}109 110limit_max = {111    "char": "CHAR_MAX",112    "uchar": "UCHAR_MAX",113    "short": "SHRT_MAX",114    "ushort": "USHRT_MAX",115    "int": "INT_MAX",116    "uint": "UINT_MAX",117    "long": "LONG_MAX",118    "ulong": "ULONG_MAX",119    "half": "0x1.ffcp+15",120}121 122limit_min = {123    "char": "CHAR_MIN",124    "uchar": "0",125    "short": "SHRT_MIN",126    "ushort": "0",127    "int": "INT_MIN",128    "uint": "0",129    "long": "LONG_MIN",130    "ulong": "0",131    "half": "-0x1.ffcp+15",132}133 134 135def conditional_guard(src, dst):136    int64_count = 0137    float64_count = 0138    float16_count = 0139    if src in int64_types:140        int64_count = int64_count + 1141    elif src in float64_types:142        float64_count = float64_count + 1143    elif src in float16_types:144        float16_count = float16_count + 1145    if dst in int64_types:146        int64_count = int64_count + 1147    elif dst in float64_types:148        float64_count = float64_count + 1149    elif dst in float16_types:150        float16_count = float16_count + 1151    if float64_count > 0 and float16_count > 0:152        print("#if defined(cl_khr_fp16) && defined(cl_khr_fp64)")153        return True154    elif float64_count > 0:155        # In embedded profile, if cl_khr_fp64 is supported cles_khr_int64 has to be156        print("#ifdef cl_khr_fp64")157        return True158    elif float16_count > 0:159        print("#if defined cl_khr_fp16")160        return True161    elif int64_count > 0:162        print("#if defined cles_khr_int64 || !defined(__EMBEDDED_PROFILE__)")163        return True164    return False165 166 167nl = "\n"168includes = []169if not clc:170    includes = ["<clc/opencl/convert.h>"]171else:172    includes = sorted(173        [174            "<clc/internal/clc.h>",175            "<clc/integer/definitions.h>",176            "<clc/float/definitions.h>",177            "<clc/integer/clc_abs.h>",178            "<clc/common/clc_sign.h>",179            "<clc/shared/clc_clamp.h>",180            "<clc/shared/clc_min.h>",181            "<clc/shared/clc_max.h>",182            "<clc/math/clc_fabs.h>",183            "<clc/math/clc_rint.h>",184            "<clc/math/clc_ceil.h>",185            "<clc/math/clc_floor.h>",186            "<clc/math/clc_nextafter.h>",187            "<clc/relational/clc_select.h>",188        ]189    )190 191print(192    f"""//===----------------------------------------------------------------------===//193//194// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.195// See https://llvm.org/LICENSE.txt for license information.196// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception197//198//===----------------------------------------------------------------------===//199//200// Automatically generated from {path.basename(__file__)}, do not edit!201//202// OpenCL type conversion functions203//204//===----------------------------------------------------------------------===//205 206{nl.join(['#include ' + f for f in includes])}207#include <clc/clc_convert.h>208 209#ifdef cl_khr_fp16210#pragma OPENCL EXTENSION cl_khr_fp16 : enable211#endif212 213#ifdef cl_khr_fp64214#pragma OPENCL EXTENSION cl_khr_fp64 : enable215 216#if defined(__EMBEDDED_PROFILE__) && !defined(cles_khr_int64)217#error Embedded profile that supports cl_khr_fp64 also has to support cles_khr_int64218#endif219 220#endif221 222#ifdef cles_khr_int64223#pragma OPENCL EXTENSION cles_khr_int64 : enable224#endif225 226"""227)228 229 230#231# Default Conversions232#233# All conversions are in accordance with the OpenCL specification,234# which cites the C99 conversion rules.235#236# Casting from floating point to integer results in conversions237# with truncation, so it should be suitable for the default convert238# functions.239#240# Conversions from integer to floating-point, and floating-point to241# floating-point through casting is done with the default rounding242# mode. While C99 allows dynamically changing the rounding mode243# during runtime, it is not a supported feature in OpenCL according244# to Section 7.1 - Rounding Modes in the OpenCL 1.2 specification.245#246# Therefore, we can assume for optimization purposes that the247# rounding mode is fixed to round-to-nearest-even. Platform target248# authors should ensure that the rounding-control registers remain249# in this state, and that this invariant holds.250#251# Also note, even though the OpenCL specification isn't entirely252# clear on this matter, we implement all rounding mode combinations253# even for integer-to-integer conversions. When such a conversion254# is used, the rounding mode is ignored.255#256def print_passthru_conversion(src_ty, dst_ty, fn_name):257    print(258        f"""_CLC_DEF _CLC_OVERLOAD {dst_ty} {fn_name}({src_ty} x) {{259  return __clc_{fn_name}(x);260}}261"""262    )263 264 265def generate_default_conversion(src, dst, mode):266    close_conditional = conditional_guard(src, dst)267 268    for size in vector_sizes:269        if not size:270            if clc:271                print(272                    f"""_CLC_DEF _CLC_OVERLOAD {dst} __clc_convert_{dst}{mode}({src} x) {{273  return ({dst})x;274}}275"""276                )277            else:278                print_passthru_conversion(src, dst, f"convert_{dst}{mode}")279        else:280            if clc:281                print(282                    f"""_CLC_DEF _CLC_OVERLOAD {dst}{size} __clc_convert_{dst}{size}{mode}({src}{size} x) {{283  return __builtin_convertvector(x, {dst}{size});284}}285"""286                )287            else:288                print_passthru_conversion(289                    f"{src}{size}", f"{dst}{size}", f"convert_{dst}{size}{mode}"290                )291 292    if close_conditional:293        print("#endif")294 295 296# Do not generate user-facing default conversions for clspv as they are handled297# natively298if not clspv:299    for src in types:300        for dst in types:301            generate_default_conversion(src, dst, "")302 303for src in int_types:304    for dst in int_types:305        for mode in rounding_modes:306            # Do not generate user-facing "_rte" conversions for clspv as they307            # are handled natively308            if clspv and mode == "_rte":309                continue310            generate_default_conversion(src, dst, mode)311 312#313# Saturated Conversions To Integers314 315 316# These functions are dependent on the unsaturated conversion functions317# generated above, and use clamp, max, min, and select to eliminate318# branching and vectorize the conversions.319#320# Again, as above, we allow all rounding modes for integer-to-integer321# conversions with saturation.322#323def generate_saturated_conversion(src, dst, size):324    # Header325    close_conditional = conditional_guard(src, dst)326 327    dstn = f"{dst}{size}"328    srcn = f"{src}{size}"329 330    if not clc:331        print_passthru_conversion(f"{srcn}", f"{dstn}", f"convert_{dstn}_sat")332        if close_conditional:333            print("#endif")334        return335 336    print(f"_CLC_DEF _CLC_OVERLOAD {dstn} __clc_convert_{dstn}_sat({srcn} x) {{")337 338    # FIXME: This is a work around for lack of select function with signed339    # third argument when the first two arguments are unsigned types. We cast340    # to the signed type for sign-extension, then do a bitcast to the unsigned341    # type.342    if dst in unsigned_types:343        bool_prefix = f"__clc_as_{dstn}(__clc_convert_{bool_type[dst]}{size}"344        bool_suffix = ")"345    else:346        bool_prefix = f"__clc_convert_{bool_type[dst]}{size}"347        bool_suffix = ""348 349    dst_max = limit_max[dst]350    dst_min = limit_min[dst]351 352    # Body353    if src == dst:354        # Conversion between same types355        print("  return x;")356 357    elif src in float_types:358        # Conversion from float to int359        print(360            f"""  {dstn} y = __clc_convert_{dstn}(x);361  y = __clc_select(y, ({dstn}){dst_min}, {bool_prefix}(x <= ({srcn}){dst_min}){bool_suffix});362  y = __clc_select(y, ({dstn}){dst_max}, {bool_prefix}(x >= ({srcn}){dst_max}){bool_suffix});363  return y;"""364        )365    else:366        # Integer to integer convesion with sizeof(src) == sizeof(dst)367        if sizeof_type[src] == sizeof_type[dst]:368            if src in unsigned_types:369                print(f"  x = __clc_min(x, ({src}){dst_max});")370            else:371                print(f"  x = __clc_max(x, ({src})0);")372 373        # Integer to integer conversion where sizeof(src) > sizeof(dst)374        elif sizeof_type[src] > sizeof_type[dst]:375            if src in unsigned_types:376                print(f"  x = __clc_min(x, ({src}){dst_max});")377            else:378                print(f"  x = __clc_clamp(x, ({src}){dst_min}, ({src}){dst_max});")379 380        # Integer to integer conversion where sizeof(src) < sizeof(dst)381        elif src not in unsigned_types and dst in unsigned_types:382            print(f"  x = __clc_max(x, ({src})0);")383 384        print(f"  return __clc_convert_{dstn}(x);")385 386    # Footer387    print("}")388    if close_conditional:389        print("#endif")390 391 392for src in types:393    for dst in int_types:394        for size in vector_sizes:395            generate_saturated_conversion(src, dst, size)396 397 398def generate_saturated_conversion_with_rounding(src, dst, size, mode):399    # Header400    close_conditional = conditional_guard(src, dst)401 402    dstn = f"{dst}{size}"403    srcn = f"{src}{size}"404 405    if not clc:406        print_passthru_conversion(f"{srcn}", f"{dstn}", f"convert_{dstn}_sat{mode}")407    else:408        # Body409        print(410            f"""_CLC_DEF _CLC_OVERLOAD {dstn} __clc_convert_{dstn}_sat{mode}({srcn} x) {{411  return __clc_convert_{dstn}_sat(x);412}}413"""414        )415 416    # Footer417    if close_conditional:418        print("#endif")419 420 421for src in int_types:422    for dst in int_types:423        for size in vector_sizes:424            for mode in rounding_modes:425                generate_saturated_conversion_with_rounding(src, dst, size, mode)426 427 428#429# Conversions To/From Floating-Point With Rounding430#431# Note that we assume as above that casts from floating-point to432# integer are done with truncation, and that the default rounding433# mode is fixed to round-to-nearest-even, as per C99 and OpenCL434# rounding rules.435#436# These functions rely on the use of abs, ceil, fabs, floor,437# nextafter, sign, rint and the above generated conversion functions.438#439# Only conversions to integers can have saturation.440#441def generate_float_conversion(src, dst, size, mode, sat):442    # Header443    close_conditional = conditional_guard(src, dst)444 445    dstn = f"{dst}{size}"446    srcn = f"{src}{size}"447    booln = f"{bool_type[dst]}{size}"448    src_max = limit_max[src] if src in limit_max else ""449    dst_min = limit_min[dst] if dst in limit_min else ""450 451    if not clc:452        print_passthru_conversion(f"{srcn}", f"{dstn}", f"convert_{dstn}{sat}{mode}")453        # Footer454        if close_conditional:455            print("#endif")456        return457 458    print(f"_CLC_DEF _CLC_OVERLOAD {dstn} __clc_convert_{dstn}{sat}{mode}({srcn} x) {{")459 460    # Perform conversion461    if dst in int_types:462        if mode == "_rte":463            print("  x = __clc_rint(x);")464        elif mode == "_rtp":465            print("  x = __clc_ceil(x);")466        elif mode == "_rtn":467            print("  x = __clc_floor(x);")468        print(f"  return __clc_convert_{dstn}{sat}(x);")469    elif mode == "_rte":470        print(f"  return __clc_convert_{dstn}(x);")471    else:472        print(f"  {dstn} r = __clc_convert_{dstn}(x);")473        if src in int_types:474            print(f"  {srcn} y = __clc_convert_{srcn}_sat(r);")475        else:476            print(f"  {srcn} y = __clc_convert_{srcn}(r);")477        if mode == "_rtz":478            if src in int_types:479                usrcn = f"{unsigned_type[src]}{size}"480                print(f"  {usrcn} abs_x = __clc_abs(x);")481                print(f"  {usrcn} abs_y = __clc_abs(y);")482            else:483                print(f"  {srcn} abs_x = __clc_fabs(x);")484                print(f"  {srcn} abs_y = __clc_fabs(y);")485            print(f"  {booln} c = __clc_convert_{booln}(abs_y > abs_x);")486            if sizeof_type[src] >= sizeof_type[dst] and src in int_types:487                print(f"  c = c || __clc_convert_{booln}(({srcn}){src_max} == x);")488            print(489                f"  {dstn} sel = __clc_select(r, __clc_nextafter(r, __clc_sign(r) * ({dstn})-INFINITY), c);"490            )491            if dst == "half" and src in int_types and sizeof_type[src] >= 2:492                dst_max = limit_max[dst]493                # short is 16 bits signed, so the maximum value rounded to zero494                # is 0x1.ffcp+14 (0x1p+15 == 32768 > 0x7fff == 32767)495                if src == "short":496                    dst_max = "0x1.ffcp+14"497                print(498                    f"  return __clc_clamp(sel, ({dstn}){dst_min}, ({dstn}){dst_max});"499                )500            else:501                print("  return sel;")502        if mode == "_rtp":503            print(504                f"  {dstn} sel = __clc_select(r, __clc_nextafter(r, ({dstn})INFINITY), __clc_convert_{booln}(y < x));"505            )506            if dst == "half" and src in int_types and sizeof_type[src] >= 2:507                print(f"  return __clc_max(sel, ({dstn}){dst_min});")508            else:509                print("  return sel;")510        if mode == "_rtn":511            print(f"  {booln} c = __clc_convert_{booln}(y > x);")512            if sizeof_type[src] >= sizeof_type[dst] and src in int_types:513                print(f"  c = c || __clc_convert_{booln}(({srcn}){src_max} == x);")514            print(515                f"  {dstn} sel = __clc_select(r, __clc_nextafter(r, ({dstn})-INFINITY), c);"516            )517            if dst == "half" and src in int_types and sizeof_type[src] >= 2:518                dst_max = limit_max[dst]519                # short is 16 bits signed, so the maximum value rounded to520                # negative infinity is 0x1.ffcp+14 (0x1p+15 == 32768 > 0x7fff521                # == 32767)522                if src == "short":523                    dst_max = "0x1.ffcp+14"524                print(f"  return __clc_min(sel, ({dstn}){dst_max});")525            else:526                print("  return sel;")527 528    # Footer529    print("}")530    if close_conditional:531        print("#endif")532 533 534for src in float_types:535    for dst in int_types:536        for size in vector_sizes:537            for mode in rounding_modes:538                for sat in saturation:539                    generate_float_conversion(src, dst, size, mode, sat)540 541 542for src in types:543    for dst in float_types:544        for size in vector_sizes:545            for mode in rounding_modes:546                # Do not generate user-facing "_rte" conversions for clspv as547                # they are handled natively548                if clspv and mode == "_rte":549                    continue550                generate_float_conversion(src, dst, size, mode, "")551