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
|
# ========================== begin_copyright_notice ============================
#
# Copyright (C) 2021 Intel Corporation
#
# SPDX-License-Identifier: MIT
#
# =========================== end_copyright_notice =============================
import argparse
import os
from functools import total_ordering
from subprocess import check_call
parser = argparse.ArgumentParser(description='Apply LLVM patches for IGC')
parser.add_argument('--llvm-version', required=True,
help='LLVM version for patching')
parser.add_argument('--llvm-project-dir', required=True,
help='LLVM project copied sources')
parser.add_argument('--patches-dir', required=True,
help='Directory with patches')
parser.add_argument('--patch-executable', required=True,
help='Path to patch program')
parser.add_argument('--patch-disable', required=True,
help='Patch to disable')
parser.add_argument('--dry-run', action='store_true',
help='Only print list of patches that will be applied')
args = parser.parse_args()
def get_dir_patches(ver_dir):
"""Return list of patches from given version directory.
Collect patches from 'patches' subdirectory and return them
as a list of DirEntry objects.
"""
patches_dir = os.path.join(args.patches_dir, ver_dir)
patches = []
ext_patches = os.path.join(patches_dir, 'patches_external')
if os.path.exists(ext_patches):
patches.extend(os.scandir(ext_patches))
return patches
def apply_patch(patch_path):
"""Apply patch to llvm project."""
rel_path = os.path.relpath(patch_path.path, args.patches_dir)
print('Applying {} file'.format(rel_path))
if args.dry_run:
return
check_call([args.patch_executable,
'-t', '-s', '-N',
'-d', args.llvm_project_dir,
'-p1', '-i', patch_path])
def split_ver_str(ver_str):
"""Split version string into numeric components.
Return list of components as numbers additionally checking
that all components are correct (i.e. can be converted to numbers).
"""
ver_list = []
for c in ver_str.split('.')[0:3]:
if not c.isdecimal():
raise RuntimeError("Malformed version string '{}'. "
"Component '{}' is not an integer."
.format(ver_str, c))
ver_list.append(int(c))
return ver_list
def get_ver_component(ver_list, idx):
"""Get version component from components list.
Return 0 for components out of range as default.
"""
if idx < len(ver_list):
return ver_list[idx]
return 0
@total_ordering
class Version:
"""Simple wrapper around three-component version.
This class provides convenient accessors to version components
represented by decimal numbers. Suitable for LLVM version in IGC.
"""
def __init__(self, ver_str):
ver_list = split_ver_str(ver_str)
ver_tuple = tuple(get_ver_component(ver_list, idx) for idx in (0, 1, 2))
self.major = ver_tuple[0]
self.minor = ver_tuple[1]
self.patch = ver_tuple[2]
def as_tuple(self):
return (self.major, self.minor, self.patch)
def __repr__(self):
return '{}.{}.{}'.format(self.major, self.minor, self.patch)
def __eq__(self, other):
return self.as_tuple() == other.as_tuple()
def __lt__(self, other):
return self.as_tuple() < other.as_tuple()
required_ver = Version(args.llvm_version)
# Create mapping of version to directory with suitable
# version range sorted in descending order.
# All directories with same major version as required are suitable.
patches_dir = os.listdir(args.patches_dir)
ver_to_dir = [(Version(v), v) for v in patches_dir]
ver_to_dir = filter(lambda tpl: tpl[0].major == required_ver.major, ver_to_dir)
ver_to_dir = filter(lambda tpl: tpl[0] <= required_ver, ver_to_dir)
ver_to_dir = sorted(ver_to_dir, key=lambda tpl: tpl[0], reverse=True)
# Merge patches from suitable directories taking only patches from
# newest versions if same patch is present in several directries.
patches = {}
for _, d in ver_to_dir:
dir_patches = get_dir_patches(d)
dir_patches = {d.name : d for d in dir_patches}
dir_patches.update(patches)
patches = dir_patches
patches = list(patches.values())
patches.sort(key=lambda p: p.name)
checkDisabledPatch = False
if args.patch_disable != "None":
checkDisabledPatch = True
for patch in patches:
if checkDisabledPatch:
if args.patch_disable in patch.name:
continue
apply_patch(patch)
|