1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
#!/usr/bin/env python3
#
# Copyright (c) 2025, Intel Corporation
#
# SPDX-License-Identifier: BSD-3-Clause
import sys
import re
# Subprocess is used with default shell which is False, it's safe and doesn't allow shell injection
# so it's safe to ignore Bandit warning.
import subprocess #nosec
import platform
import argparse
from os.path import basename, dirname
from os import rename, replace
from tempfile import NamedTemporaryFile
# Read input data and put it in the form of byte array in the source file.
def write_data(src, outfile):
width = 16
with open(src, 'rb') as file:
data = file.read()
for i in range(0, len(data), 1):
outfile.write("0x%0.2X," % ord(data[i:i+1]))
if i%width == (width-1):
outfile.write("\n")
else:
outfile.write(" ")
return len(data)
return 0
def bundle_header(src, output):
name = basename(output).replace(".", "_")
with open(src, 'r') as infile:
with open(output, 'w') as outfile:
outfile.write("#include \"bitcode_lib.h\"\n\n")
outfile.write("using namespace ispc;\n\n")
outfile.write(f"extern const char {name}_header[] = ")
outfile.write("{\n")
# Read input data and put it in the form of byte array in the source file.
length = write_data(src, outfile)
outfile.write("0x00 };\n\n")
outfile.write(f"int {name}_length = {length};\n")
ARCH_CHOICES = ['i686', 'x86', 'x86_64', 'arm', 'armv8a', 'arm64', 'aarch64', 'wasm32', 'wasm64', 'xe64']
parser = argparse.ArgumentParser()
parser.add_argument("src", help="Source file to process")
parser.add_argument("output", help="Output file")
parser.add_argument("--type", help="Type of processed file", choices=['dispatch', 'builtins-c', 'ispc-target', 'stdlib', 'header'], required=True)
parser.add_argument("--runtime", help="Runtime", choices=['32', '64'], nargs='?', default='')
parser.add_argument("--os", help="Target OS", choices=['windows', 'linux', 'macos', 'freebsd', 'android', 'ios', 'ps4', 'web', 'WINDOWS', 'UNIX', 'WEB'], default='')
parser.add_argument("--arch", help="Target architecture", choices=ARCH_CHOICES, default='')
args = parser.parse_known_args()
src = args[0].src
output = args[0].output
length=0
if args[0].type == 'header':
bundle_header(src, output)
sys.exit(0)
target = basename(src)
target = re.sub(r"^builtins_", "", target)
target = re.sub(r"^target_", "", target)
target = re.sub(r"^stdlib_", "", target)
target = re.sub(r"\.bc$", "", target)
target = re.sub(r"\.ll$", "", target)
target = re.sub(r"\.c$", "", target)
target = re.sub(r"_32bit.*$$", "", target)
target = re.sub(r"_64bit.*$$", "", target)
name = target
if args[0].runtime != '':
name += "_" + args[0].runtime + "bit"
# Macro style arguments "UNIX", "WINDOWS", and "WEB" for .ll to .cpp (dispatch and targets)
if args[0].os == "UNIX":
target_os_old = "unix"
target_os = "linux"
elif args[0].os == "WINDOWS":
target_os_old = "win"
target_os = "windows"
elif args[0].os == "WEB":
target_os_old = "web"
target_os = "web"
# Exact OS names for builtins.c
elif args[0].os in ["windows", "linux", "macos", "freebsd", "android", "ios", "ps4", "web"]:
target_os_old = args[0].os
target_os = args[0].os
else:
sys.stderr.write("Unknown argument for --os: " + args[0].os + "\n")
sys.exit(1)
target_arch = ""
ispc_arch = ""
if args[0].arch in ARCH_CHOICES:
target_arch = args[0].arch + "_"
# Canoncalization of arch value for Arch enum in ISPC.
if args[0].arch == "i686" or args[0].arch == "x86":
ispc_arch = "x86"
elif args[0].arch == "x86_64" or args[0].arch == "amd64":
ispc_arch = "x86_64"
elif args[0].arch == "armv8a" or args[0].arch == "arm":
ispc_arch = "arm"
elif args[0].arch == "arm64" or args[0].arch == "aarch64":
ispc_arch = "aarch64"
elif args[0].arch == "wasm32":
ispc_arch = "wasm32"
elif args[0].arch == "wasm64":
ispc_arch = "wasm64"
elif args[0].arch == "xe64":
ispc_arch = args[0].arch
name_prefix = "stdlib_bitcode_" if args[0].type == 'stdlib' else "builtins_bitcode_"
name = name_prefix + target_os_old + "_" + target_arch + name;
# with open(output, 'w') as outfile:
with NamedTemporaryFile(mode='w', dir=dirname(output), delete=False) as outfile:
temp_file_name = outfile.name
outfile.write("#include \"bitcode_lib.h\"\n\n")
outfile.write("using namespace ispc;\n\n")
outfile.write("extern const unsigned char " + name + "[] = {\n")
length = write_data(src, outfile)
outfile.write("0x00 };\n\n")
outfile.write(f"int {name}_length = {length};\n")
# There are 3 types of bitcodes to handle (dispatch module, builtins-c, and target),
# each needs to be registered differently.
if args[0].type == "dispatch":
# For dispatch the only parameter is TargetOS.
outfile.write(f"static BitcodeLib {name}_lib({name}, {name}_length, TargetOS::{target_os});\n")
elif args[0].type == "builtins-c":
# For builtin-c we care about TargetOS and Arch.
outfile.write((f"static BitcodeLib {name}_lib({name}, {name}_length, TargetOS::{target_os}, "
f"Arch::{ispc_arch});\n"))
elif args[0].type == 'ispc-target' or args[0].type == 'stdlib':
# For ISPC target files we care about ISPCTarget id, TargetOS type (Windows/Unix), and runtime type (32/64).
arch = "error"
if ("sse" in target) or ("avx" in target):
arch = "x86" if args[0].runtime == "32" else "x86_64" if args[0].runtime == "64" else "error"
elif "neon" in target:
arch = "arm" if args[0].runtime == "32" else "aarch64" if args[0].runtime == "64" else "error"
elif "wasm" in target:
arch = "wasm32" if args[0].runtime == "32" else "wasm64" if args[0].runtime == "64" else "error"
elif ("gen9" in target) or ("xe" in target):
arch = "xe64"
elif ("generic" in target):
arch = args[0].arch
target = "_".join(target.split("_")[0:2])
else:
sys.stderr.write("Unknown target detected: " + target + "\n")
sys.exit(1)
if args[0].type == 'stdlib':
outfile.write((f"static BitcodeLib {name}_lib(BitcodeLib::BitcodeLibType::Stdlib, {name}, {name}_length, "
f"ISPCTarget::{target}, TargetOS::{target_os}, Arch::{arch});\n"))
else:
outfile.write((f"static BitcodeLib {name}_lib({name}, {name}_length, ISPCTarget::{target}, "
f"TargetOS::{target_os}, Arch::{arch});\n"))
else:
sys.stderr.write("Unknown argument for --type: " + args[0].type + "\n")
sys.exit(1)
replace(temp_file_name, output)
|