Skip to content

Commit

Permalink
[Hexagon] Rework tvm.target.hexagon() interface (apache#8823)
Browse files Browse the repository at this point in the history
* [Hexagon] Rework tvm.target.hexagon() interface

Make the tvm.target.hexagon() function take most options as keyword
parameters. This will allow adding additional parameters without changing
the interface.

No changes are required to existing code, except for changing positional
parameters following the CPU version to keyword parameters, and updating
the names of the keyword parameters:
  sim_args  -> sim_options,
  llvm_args -> llvm_options,
although the old names will be accepted for the time being.

* formatting

* change ' to "

* Rename 'args' to 'config' for clarity

* Use 'strip' instad of 'replace'

* Restart build
  • Loading branch information
Krzysztof Parzyszek authored and Andrew Zhao Luo committed Sep 1, 2021
1 parent 73c9f07 commit 2231f0d
Showing 1 changed file with 90 additions and 47 deletions.
137 changes: 90 additions & 47 deletions python/tvm/target/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,79 +413,118 @@ def bifrost(model="unknown", options=None):
return Target(" ".join(["opencl"] + opts))


def hexagon(cpu_ver="v66", sim_args=None, llvm_args=None, hvx=128):
def hexagon(cpu_ver="v66", **kwargs):
"""Returns a Hexagon target.
Parameters
----------
cpu_ver : str
cpu_ver : str (default: "v66")
CPU version used for code generation. Not all allowed cpu str
will be valid, LLVM will throw an error.
sim_args : str or list of str
Recognized keyword parameters
-----------------------------
hvx : int (default: 128)
Size of HVX vector in bytes. Value of 0 disables HVX codegen.
sim_options : str or list of str (default: None)
User defined sim arguments. CPU version defaults to cpu_ver.
Otherwise, separate versions are used for codegen and sim. Not
all allowed cpu strings will be valid, simulator will throw an
error if invalid. Does not affect codegen.
llvm_args : str or list of str
llvm_options : str or list of str (default: None)
User defined compiler arguments.
hvx : int
Size of hvx register. Value of 0 indicates disabled hvx.
"""

# Some of the target parameters correspond to target kind attributes
# listed in src/target/target_kind.cc. For those parameters, their
# names follow the attribute names with the exception of '_' being used
# in place of '-'.

# Example compiler arguments
# llvm -mtriple=hexagon -mcpu=hexagonv66 -mattr=+hvxv66,+hvx-length128b

# Check for valid codegen cpu
valid_hex = ["v60", "v62", "v65", "v66", "v67", "v67t"]
valid_hex = ["v60", "v62", "v65", "v66", "v67", "v67t", "v68"]
try:
cpu_ver = cpu_ver[cpu_ver.index("v") :].lower()
assert 3 <= len(cpu_ver) <= 4
assert cpu_ver in valid_hex
except:
msg = "{} is not a valid Hexagon version\nvalid versions include {}"
raise ValueError(msg.format(cpu_ver, valid_hex)) from None

assert hvx in [0, 64, 128]
# Target configuration:
config = {
"hvx": 128,
"sim_options": None,
"llvm_options": None,
}
config.update(kwargs)

# Warn about obsolete parameter names.
if config.get("sim_args"):
msg = "The keyword parameter 'sim_args' is deprecated, use 'sim_options' instead"
warnings.warn(msg, stacklevel=2)
config.update({"sim_options": config["sim_args"]})
if config.get("llvm_args"):
msg = "The keyword parameter 'llvm_args' is deprecated, use 'llvm_options' instead"
warnings.warn(msg, stacklevel=2)
config.update({"llvm_options": config["llvm_args"]})

# LLVM target string
def create_llvm_target(cpu_ver, config):
""" Create LLVM target string. """

# Target string
def create_target(cpu_ver):
target = " -mtriple=hexagon"
mcpu = " -mcpu=hexagon" + cpu_ver
mattr = ""
# HVX enable
if hvx:
mattr = " -mattr=+hvx" + cpu_ver + ",+hvx-length" + str(hvx) + "b"
return target + mcpu + mattr

# Simulator string
def create_sim(cpu_ver, sim_args):
def validate_hvx_length(codegen_hvx, sim_args):
if sim_args and "--hvx_length" in sim_args:

# Process the options that affect target features and return the
# target feature string.
def create_target_features(config):
tfs = []
if config["hvx"] > 0:
valid_hvx = [0, 64, 128]
if not config["hvx"] in valid_hvx:
raise ValueError("Invalid hvx value, should be one of " + str(valid_hvx))
tfs += ["+hvx" + cpu_ver, "+hvx-length" + str(config["hvx"]) + "b"]
else:
tfs += ["-hvx"]
return "-mattr=" + ",".join(tfs) if tfs else ""

return target + mcpu + " " + create_target_features(config)

# Simulator options string
def create_sim_options(cpu_ver, config):
""" Create simulator option string. """

def validate_hvx_length(codegen_hvx, sim_options):
if sim_options and "--hvx_length" in sim_options:
# If --hvx_length was specified, check HVX length of sim
# vs codegen
i = sim_args.index("hvx_length") + len("hvx_length") + 1
sim_hvx = sim_args[i : i + 3]
i = sim_options.index("hvx_length") + len("hvx_length") + 1
sim_hvx = sim_options[i : i + 3]
if sim_hvx != str(codegen_hvx):
print(
"WARNING: sim hvx {} and codegen hvx {} mismatch!".format(
sim_hvx, codegen_hvx
)
)
msg = "sim hvx {} and codegen hvx {} mismatch!".format(sim_hvx, codegen_hvx)
# Set the stacklevel to the tvm.target.hexagon() call.
warnings.warn(msg, stacklevel=4)
elif codegen_hvx != 0:
# If --hvx_length was not given, add it if HVX is enabled
sim_args = sim_args + " " if isinstance(sim_args, str) else ""
sim_args += "--hvx_length " + str(codegen_hvx)
return sim_args or ""
sim_options = sim_options + " " if isinstance(sim_options, str) else ""
sim_options += "--hvx_length " + str(codegen_hvx)
return sim_options or ""

if not sim_args:
return cpu_ver + " " + validate_hvx_length(hvx, sim_args)
hvx = config["hvx"]
sim_options = config["sim_options"]
if not sim_options:
return cpu_ver + " " + validate_hvx_length(hvx, sim_options)

sim_cpu = cpu_ver + " "

# Add user defined args
if isinstance(sim_args, list):
sim_args = " ".join(sim_args)
if isinstance(sim_options, list):
sim_options = " ".join(sim_options)

# Check for supplied sim cpu version
if "v6" in sim_args:
if "v6" in sim_options:
sim_cpu = ""

# Regex match for allowed cpus
Expand All @@ -494,13 +533,13 @@ def validate_hvx_length(codegen_hvx, sim_args):
+ r"(?P<base_version>v6[25678])(?P<sub_version>[a-z])?"
+ r"(?P<l2_size>_[0-9]+)?(?P<rev>_rev[0-9])?\s?(?P<post>--.*)?"
)
m = re.match(valid_cpu_str_regex, sim_args.lower())
m = re.match(valid_cpu_str_regex, sim_options.lower())
if not m:
raise ValueError('Invalid simulator argument string "{}"'.format(sim_args))
raise ValueError('Invalid simulator argument string "{}"'.format(sim_options))

# Parse options into correct order
cpu_attr = {x: str(m.groupdict()[x] or "") for x in m.groupdict()}
sim_args = (
sim_options = (
cpu_attr["base_version"]
+ cpu_attr["sub_version"]
+ cpu_attr["l2_size"]
Expand All @@ -510,23 +549,27 @@ def validate_hvx_length(codegen_hvx, sim_args):
+ cpu_attr["post"]
)

return sim_cpu + " " + validate_hvx_length(hvx, sim_args)
return sim_cpu + " " + validate_hvx_length(hvx, sim_options)

# LLVM options string
def create_llvm_options(cpu_ver, config): # pylint: disable=unused-argument
""" Create LLVM options string. """

llvm_options = config["llvm_options"]

# LLVM string
def create_llvm(llvm_args):
# TVM's option parser doesn't allow '=' in values, but '=' can
# appear in LLVM flags. Replace it with '@', since it's unlikely
# that '@' will be used in another context.
if llvm_args is None or len(llvm_args.replace(" ", "")) == 0:
if llvm_options is None or len(llvm_options.strip()) == 0:
return ""
args = [s.replace("=", "@") for s in llvm_args.split()]
args = [s.replace("=", "@") for s in llvm_options.split()]
return "--llvm-options=" + ",".join(args)

# Sim args
os.environ["HEXAGON_SIM_ARGS"] = create_sim(cpu_ver, sim_args)
os.environ["HEXAGON_SIM_ARGS"] = create_sim_options(cpu_ver, config)

target_str = create_target(cpu_ver)
llvm_str = create_llvm(llvm_args)
target_str = create_llvm_target(cpu_ver, config)
llvm_str = create_llvm_options(cpu_ver, config)
args_list = target_str.split() + llvm_str.split()

return Target(" ".join(["hexagon"] + args_list))
Expand Down

0 comments on commit 2231f0d

Please sign in to comment.