reach-vb's picture
reach-vb HF staff
662f462e0f601fcce9aec0bf0aceeab3e0c0e219783432fa02431d37567ec282
c65f48d
raw
history blame
No virus
31.8 kB
"""
Implementation of LLVM IR instructions.
"""
from llvmlite.ir import types
from llvmlite.ir.values import (Block, Function, Value, NamedValue, Constant,
MetaDataArgument, MetaDataString, AttributeSet,
Undefined, ArgumentAttributes)
from llvmlite.ir._utils import _HasMetadata
class Instruction(NamedValue, _HasMetadata):
def __init__(self, parent, typ, opname, operands, name='', flags=()):
super(Instruction, self).__init__(parent, typ, name=name)
assert isinstance(parent, Block)
assert isinstance(flags, (tuple, list))
self.opname = opname
self.operands = operands
self.flags = list(flags)
self.metadata = {}
@property
def function(self):
return self.parent.function
@property
def module(self):
return self.parent.function.module
def descr(self, buf):
opname = self.opname
if self.flags:
opname = ' '.join([opname] + self.flags)
operands = ', '.join([op.get_reference() for op in self.operands])
typ = self.type
metadata = self._stringify_metadata(leading_comma=True)
buf.append("{0} {1} {2}{3}\n"
.format(opname, typ, operands, metadata))
def replace_usage(self, old, new):
if old in self.operands:
ops = []
for op in self.operands:
ops.append(new if op is old else op)
self.operands = tuple(ops)
self._clear_string_cache()
def __repr__(self):
return "<ir.%s %r of type '%s', opname %r, operands %r>" % (
self.__class__.__name__, self.name, self.type,
self.opname, self.operands)
class CallInstrAttributes(AttributeSet):
_known = frozenset(['noreturn', 'nounwind', 'readonly', 'readnone',
'noinline', 'alwaysinline'])
TailMarkerOptions = frozenset(['tail', 'musttail', 'notail'])
class FastMathFlags(AttributeSet):
_known = frozenset(['fast', 'nnan', 'ninf', 'nsz', 'arcp', 'contract',
'afn', 'reassoc'])
class CallInstr(Instruction):
def __init__(self, parent, func, args, name='', cconv=None, tail=None,
fastmath=(), attrs=(), arg_attrs=None):
self.cconv = (func.calling_convention
if cconv is None and isinstance(func, Function)
else cconv)
# For backwards compatibility with previous API of accepting a "truthy"
# value for a hint to the optimizer to potentially tail optimize.
if isinstance(tail, str) and tail in TailMarkerOptions:
pass
elif tail:
tail = "tail"
else:
tail = ""
self.tail = tail
self.fastmath = FastMathFlags(fastmath)
self.attributes = CallInstrAttributes(attrs)
self.arg_attributes = {}
if arg_attrs:
for idx, attrs in arg_attrs.items():
if not (0 <= idx < len(args)):
raise ValueError("Invalid argument index {}"
.format(idx))
self.arg_attributes[idx] = ArgumentAttributes(attrs)
# Fix and validate arguments
args = list(args)
for i in range(len(func.function_type.args)):
arg = args[i]
expected_type = func.function_type.args[i]
if (isinstance(expected_type, types.MetaDataType) and
arg.type != expected_type):
arg = MetaDataArgument(arg)
if arg.type != expected_type:
msg = ("Type of #{0} arg mismatch: {1} != {2}"
.format(1 + i, expected_type, arg.type))
raise TypeError(msg)
args[i] = arg
super(CallInstr, self).__init__(parent, func.function_type.return_type,
"call", [func] + list(args), name=name)
@property
def callee(self):
return self.operands[0]
@callee.setter
def callee(self, newcallee):
self.operands[0] = newcallee
@property
def args(self):
return self.operands[1:]
def replace_callee(self, newfunc):
if newfunc.function_type != self.callee.function_type:
raise TypeError("New function has incompatible type")
self.callee = newfunc
@property
def called_function(self):
"""The callee function"""
return self.callee
def _descr(self, buf, add_metadata):
def descr_arg(i, a):
if i in self.arg_attributes:
attrs = ' '.join(self.arg_attributes[i]._to_list(a.type)) + ' '
else:
attrs = ''
return '{0} {1}{2}'.format(a.type, attrs, a.get_reference())
args = ', '.join([descr_arg(i, a) for i, a in enumerate(self.args)])
fnty = self.callee.function_type
# Only print function type if variable-argument
if fnty.var_arg:
ty = fnty
# Otherwise, just print the return type.
else:
# Fastmath flag work only in this case
ty = fnty.return_type
callee_ref = "{0} {1}".format(ty, self.callee.get_reference())
if self.cconv:
callee_ref = "{0} {1}".format(self.cconv, callee_ref)
tail_marker = ""
if self.tail:
tail_marker = "{0} ".format(self.tail)
fn_attrs = ' ' + ' '.join(self.attributes._to_list(fnty.return_type))\
if self.attributes else ''
fm_attrs = ' ' + ' '.join(self.fastmath._to_list(fnty.return_type))\
if self.fastmath else ''
buf.append("{tail}{op}{fastmath} {callee}({args}){attr}{meta}\n".format(
tail=tail_marker,
op=self.opname,
callee=callee_ref,
fastmath=fm_attrs,
args=args,
attr=fn_attrs,
meta=(self._stringify_metadata(leading_comma=True)
if add_metadata else ""),
))
def descr(self, buf):
self._descr(buf, add_metadata=True)
class InvokeInstr(CallInstr):
def __init__(self, parent, func, args, normal_to, unwind_to, name='',
cconv=None, fastmath=(), attrs=(), arg_attrs=None):
assert isinstance(normal_to, Block)
assert isinstance(unwind_to, Block)
super(InvokeInstr, self).__init__(parent, func, args, name, cconv,
tail=False, fastmath=fastmath,
attrs=attrs, arg_attrs=arg_attrs)
self.opname = "invoke"
self.normal_to = normal_to
self.unwind_to = unwind_to
def descr(self, buf):
super(InvokeInstr, self)._descr(buf, add_metadata=False)
buf.append(" to label {0} unwind label {1}{metadata}\n".format(
self.normal_to.get_reference(),
self.unwind_to.get_reference(),
metadata=self._stringify_metadata(leading_comma=True),
))
class Terminator(Instruction):
def __init__(self, parent, opname, operands):
super(Terminator, self).__init__(parent, types.VoidType(), opname,
operands)
def descr(self, buf):
opname = self.opname
operands = ', '.join(["{0} {1}".format(op.type, op.get_reference())
for op in self.operands])
metadata = self._stringify_metadata(leading_comma=True)
buf.append("{0} {1}{2}".format(opname, operands, metadata))
class PredictableInstr(Instruction):
def set_weights(self, weights):
operands = [MetaDataString(self.module, "branch_weights")]
for w in weights:
if w < 0:
raise ValueError("branch weight must be a positive integer")
operands.append(Constant(types.IntType(32), w))
md = self.module.add_metadata(operands)
self.set_metadata("prof", md)
class Ret(Terminator):
def __init__(self, parent, opname, return_value=None):
operands = [return_value] if return_value is not None else []
super(Ret, self).__init__(parent, opname, operands)
@property
def return_value(self):
if self.operands:
return self.operands[0]
else:
return None
def descr(self, buf):
return_value = self.return_value
metadata = self._stringify_metadata(leading_comma=True)
if return_value is not None:
buf.append("{0} {1} {2}{3}\n"
.format(self.opname, return_value.type,
return_value.get_reference(),
metadata))
else:
buf.append("{0}{1}\n".format(self.opname, metadata))
class Branch(Terminator):
pass
class ConditionalBranch(PredictableInstr, Terminator):
pass
class IndirectBranch(PredictableInstr, Terminator):
def __init__(self, parent, opname, addr):
super(IndirectBranch, self).__init__(parent, opname, [addr])
self.destinations = []
@property
def address(self):
return self.operands[0]
def add_destination(self, block):
assert isinstance(block, Block)
self.destinations.append(block)
def descr(self, buf):
destinations = ["label {0}".format(blk.get_reference())
for blk in self.destinations]
buf.append("indirectbr {0} {1}, [{2}] {3}\n".format(
self.address.type,
self.address.get_reference(),
', '.join(destinations),
self._stringify_metadata(leading_comma=True),
))
class SwitchInstr(PredictableInstr, Terminator):
def __init__(self, parent, opname, val, default):
super(SwitchInstr, self).__init__(parent, opname, [val])
self.default = default
self.cases = []
@property
def value(self):
return self.operands[0]
def add_case(self, val, block):
assert isinstance(block, Block)
if not isinstance(val, Value):
val = Constant(self.value.type, val)
self.cases.append((val, block))
def descr(self, buf):
cases = ["{0} {1}, label {2}".format(val.type, val.get_reference(),
blk.get_reference())
for val, blk in self.cases]
buf.append("switch {0} {1}, label {2} [{3}] {4}\n".format(
self.value.type,
self.value.get_reference(),
self.default.get_reference(),
' '.join(cases),
self._stringify_metadata(leading_comma=True),
))
class Resume(Terminator):
pass
class SelectInstr(Instruction):
def __init__(self, parent, cond, lhs, rhs, name='', flags=()):
assert lhs.type == rhs.type
super(SelectInstr, self).__init__(parent, lhs.type, "select",
[cond, lhs, rhs], name=name,
flags=flags)
@property
def cond(self):
return self.operands[0]
@property
def lhs(self):
return self.operands[1]
@property
def rhs(self):
return self.operands[2]
def descr(self, buf):
buf.append("select {0} {1} {2}, {3} {4}, {5} {6} {7}\n".format(
' '.join(self.flags),
self.cond.type, self.cond.get_reference(),
self.lhs.type, self.lhs.get_reference(),
self.rhs.type, self.rhs.get_reference(),
self._stringify_metadata(leading_comma=True),
))
class CompareInstr(Instruction):
# Define the following in subclasses
OPNAME = 'invalid-compare'
VALID_OP = {}
def __init__(self, parent, op, lhs, rhs, name='', flags=[]):
if op not in self.VALID_OP:
raise ValueError("invalid comparison %r for %s" % (op, self.OPNAME))
for flag in flags:
if flag not in self.VALID_FLAG:
raise ValueError("invalid flag %r for %s" % (flag, self.OPNAME))
opname = self.OPNAME
if isinstance(lhs.type, types.VectorType):
typ = types.VectorType(types.IntType(1), lhs.type.count)
else:
typ = types.IntType(1)
super(CompareInstr, self).__init__(parent, typ,
opname, [lhs, rhs], flags=flags,
name=name)
self.op = op
def descr(self, buf):
buf.append("{opname}{flags} {op} {ty} {lhs}, {rhs} {meta}\n".format(
opname=self.opname,
flags=''.join(' ' + it for it in self.flags),
op=self.op,
ty=self.operands[0].type,
lhs=self.operands[0].get_reference(),
rhs=self.operands[1].get_reference(),
meta=self._stringify_metadata(leading_comma=True),
))
class ICMPInstr(CompareInstr):
OPNAME = 'icmp'
VALID_OP = {
'eq': 'equal',
'ne': 'not equal',
'ugt': 'unsigned greater than',
'uge': 'unsigned greater or equal',
'ult': 'unsigned less than',
'ule': 'unsigned less or equal',
'sgt': 'signed greater than',
'sge': 'signed greater or equal',
'slt': 'signed less than',
'sle': 'signed less or equal',
}
VALID_FLAG = set()
class FCMPInstr(CompareInstr):
OPNAME = 'fcmp'
VALID_OP = {
'false': 'no comparison, always returns false',
'oeq': 'ordered and equal',
'ogt': 'ordered and greater than',
'oge': 'ordered and greater than or equal',
'olt': 'ordered and less than',
'ole': 'ordered and less than or equal',
'one': 'ordered and not equal',
'ord': 'ordered (no nans)',
'ueq': 'unordered or equal',
'ugt': 'unordered or greater than',
'uge': 'unordered or greater than or equal',
'ult': 'unordered or less than',
'ule': 'unordered or less than or equal',
'une': 'unordered or not equal',
'uno': 'unordered (either nans)',
'true': 'no comparison, always returns true',
}
VALID_FLAG = {'nnan', 'ninf', 'nsz', 'arcp', 'contract', 'afn', 'reassoc',
'fast'}
class CastInstr(Instruction):
def __init__(self, parent, op, val, typ, name=''):
super(CastInstr, self).__init__(parent, typ, op, [val], name=name)
def descr(self, buf):
buf.append("{0} {1} {2} to {3} {4}\n".format(
self.opname,
self.operands[0].type,
self.operands[0].get_reference(),
self.type,
self._stringify_metadata(leading_comma=True),
))
class LoadInstr(Instruction):
def __init__(self, parent, ptr, name=''):
super(LoadInstr, self).__init__(parent, ptr.type.pointee, "load",
[ptr], name=name)
self.align = None
def descr(self, buf):
[val] = self.operands
if self.align is not None:
align = ', align %d' % (self.align)
else:
align = ''
buf.append("load {0}, {1} {2}{3}{4}\n".format(
val.type.pointee,
val.type,
val.get_reference(),
align,
self._stringify_metadata(leading_comma=True),
))
class StoreInstr(Instruction):
def __init__(self, parent, val, ptr):
super(StoreInstr, self).__init__(parent, types.VoidType(), "store",
[val, ptr])
def descr(self, buf):
val, ptr = self.operands
if self.align is not None:
align = ', align %d' % (self.align)
else:
align = ''
buf.append("store {0} {1}, {2} {3}{4}{5}\n".format(
val.type,
val.get_reference(),
ptr.type,
ptr.get_reference(),
align,
self._stringify_metadata(leading_comma=True),
))
class LoadAtomicInstr(Instruction):
def __init__(self, parent, ptr, ordering, align, name=''):
super(LoadAtomicInstr, self).__init__(parent, ptr.type.pointee,
"load atomic", [ptr], name=name)
self.ordering = ordering
self.align = align
def descr(self, buf):
[val] = self.operands
buf.append("load atomic {0}, {1} {2} {3}, align {4}{5}\n".format(
val.type.pointee,
val.type,
val.get_reference(),
self.ordering,
self.align,
self._stringify_metadata(leading_comma=True),
))
class StoreAtomicInstr(Instruction):
def __init__(self, parent, val, ptr, ordering, align):
super(StoreAtomicInstr, self).__init__(parent, types.VoidType(),
"store atomic", [val, ptr])
self.ordering = ordering
self.align = align
def descr(self, buf):
val, ptr = self.operands
buf.append("store atomic {0} {1}, {2} {3} {4}, align {5}{6}\n".format(
val.type,
val.get_reference(),
ptr.type,
ptr.get_reference(),
self.ordering,
self.align,
self._stringify_metadata(leading_comma=True),
))
class AllocaInstr(Instruction):
def __init__(self, parent, typ, count, name):
operands = [count] if count else ()
super(AllocaInstr, self).__init__(parent, typ.as_pointer(), "alloca",
operands, name)
self.align = None
def descr(self, buf):
buf.append("{0} {1}".format(self.opname, self.type.pointee))
if self.operands:
op, = self.operands
buf.append(", {0} {1}".format(op.type, op.get_reference()))
if self.align is not None:
buf.append(", align {0}".format(self.align))
if self.metadata:
buf.append(self._stringify_metadata(leading_comma=True))
class GEPInstr(Instruction):
def __init__(self, parent, ptr, indices, inbounds, name):
typ = ptr.type
lasttyp = None
lastaddrspace = 0
for i in indices:
lasttyp, typ = typ, typ.gep(i)
# inherit the addrspace from the last seen pointer
if isinstance(lasttyp, types.PointerType):
lastaddrspace = lasttyp.addrspace
if (not isinstance(typ, types.PointerType) and
isinstance(lasttyp, types.PointerType)):
typ = lasttyp
else:
typ = typ.as_pointer(lastaddrspace)
super(GEPInstr, self).__init__(parent, typ, "getelementptr",
[ptr] + list(indices), name=name)
self.pointer = ptr
self.indices = indices
self.inbounds = inbounds
def descr(self, buf):
indices = ['{0} {1}'.format(i.type, i.get_reference())
for i in self.indices]
op = "getelementptr inbounds" if self.inbounds else "getelementptr"
buf.append("{0} {1}, {2} {3}, {4} {5}\n".format(
op,
self.pointer.type.pointee,
self.pointer.type,
self.pointer.get_reference(),
', '.join(indices),
self._stringify_metadata(leading_comma=True),
))
class PhiInstr(Instruction):
def __init__(self, parent, typ, name, flags=()):
super(PhiInstr, self).__init__(parent, typ, "phi", (), name=name,
flags=flags)
self.incomings = []
def descr(self, buf):
incs = ', '.join('[{0}, {1}]'.format(v.get_reference(),
b.get_reference())
for v, b in self.incomings)
buf.append("phi {0} {1} {2} {3}\n".format(
' '.join(self.flags),
self.type,
incs,
self._stringify_metadata(leading_comma=True),
))
def add_incoming(self, value, block):
assert isinstance(block, Block)
self.incomings.append((value, block))
def replace_usage(self, old, new):
self.incomings = [((new if val is old else val), blk)
for (val, blk) in self.incomings]
class ExtractElement(Instruction):
def __init__(self, parent, vector, index, name=''):
if not isinstance(vector.type, types.VectorType):
raise TypeError("vector needs to be of VectorType.")
if not isinstance(index.type, types.IntType):
raise TypeError("index needs to be of IntType.")
typ = vector.type.element
super(ExtractElement, self).__init__(parent, typ, "extractelement",
[vector, index], name=name)
def descr(self, buf):
operands = ", ".join("{0} {1}".format(
op.type, op.get_reference()) for op in self.operands)
buf.append("{opname} {operands}\n".format(
opname=self.opname, operands=operands))
class InsertElement(Instruction):
def __init__(self, parent, vector, value, index, name=''):
if not isinstance(vector.type, types.VectorType):
raise TypeError("vector needs to be of VectorType.")
if not value.type == vector.type.element:
raise TypeError(
"value needs to be of type {} not {}.".format(
vector.type.element, value.type))
if not isinstance(index.type, types.IntType):
raise TypeError("index needs to be of IntType.")
typ = vector.type
super(InsertElement, self).__init__(parent, typ, "insertelement",
[vector, value, index], name=name)
def descr(self, buf):
operands = ", ".join("{0} {1}".format(
op.type, op.get_reference()) for op in self.operands)
buf.append("{opname} {operands}\n".format(
opname=self.opname, operands=operands))
class ShuffleVector(Instruction):
def __init__(self, parent, vector1, vector2, mask, name=''):
if not isinstance(vector1.type, types.VectorType):
raise TypeError("vector1 needs to be of VectorType.")
if vector2 != Undefined:
if vector2.type != vector1.type:
raise TypeError("vector2 needs to be " +
"Undefined or of the same type as vector1.")
if (not isinstance(mask, Constant) or
not isinstance(mask.type, types.VectorType) or
not (isinstance(mask.type.element, types.IntType) and
mask.type.element.width == 32)):
raise TypeError("mask needs to be a constant i32 vector.")
typ = types.VectorType(vector1.type.element, mask.type.count)
index_range = range(vector1.type.count
if vector2 == Undefined
else 2 * vector1.type.count)
if not all(ii.constant in index_range for ii in mask.constant):
raise IndexError(
"mask values need to be in {0}".format(index_range),
)
super(ShuffleVector, self).__init__(parent, typ, "shufflevector",
[vector1, vector2, mask], name=name)
def descr(self, buf):
buf.append("shufflevector {0} {1}\n".format(
", ".join("{0} {1}".format(op.type, op.get_reference())
for op in self.operands),
self._stringify_metadata(leading_comma=True),
))
class ExtractValue(Instruction):
def __init__(self, parent, agg, indices, name=''):
typ = agg.type
try:
for i in indices:
typ = typ.elements[i]
except (AttributeError, IndexError):
raise TypeError("Can't index at %r in %s"
% (list(indices), agg.type))
super(ExtractValue, self).__init__(parent, typ, "extractvalue",
[agg], name=name)
self.aggregate = agg
self.indices = indices
def descr(self, buf):
indices = [str(i) for i in self.indices]
buf.append("extractvalue {0} {1}, {2} {3}\n".format(
self.aggregate.type,
self.aggregate.get_reference(),
', '.join(indices),
self._stringify_metadata(leading_comma=True),
))
class InsertValue(Instruction):
def __init__(self, parent, agg, elem, indices, name=''):
typ = agg.type
try:
for i in indices:
typ = typ.elements[i]
except (AttributeError, IndexError):
raise TypeError("Can't index at %r in %s"
% (list(indices), agg.type))
if elem.type != typ:
raise TypeError("Can only insert %s at %r in %s: got %s"
% (typ, list(indices), agg.type, elem.type))
super(InsertValue, self).__init__(parent, agg.type, "insertvalue",
[agg, elem], name=name)
self.aggregate = agg
self.value = elem
self.indices = indices
def descr(self, buf):
indices = [str(i) for i in self.indices]
buf.append("insertvalue {0} {1}, {2} {3}, {4} {5}\n".format(
self.aggregate.type, self.aggregate.get_reference(),
self.value.type, self.value.get_reference(),
', '.join(indices),
self._stringify_metadata(leading_comma=True),
))
class Unreachable(Instruction):
def __init__(self, parent):
super(Unreachable, self).__init__(parent, types.VoidType(),
"unreachable", (), name='')
def descr(self, buf):
buf += (self.opname, "\n")
class InlineAsm(object):
def __init__(self, ftype, asm, constraint, side_effect=False):
self.type = ftype.return_type
self.function_type = ftype
self.asm = asm
self.constraint = constraint
self.side_effect = side_effect
def descr(self, buf):
sideeffect = 'sideeffect' if self.side_effect else ''
fmt = 'asm {sideeffect} "{asm}", "{constraint}"\n'
buf.append(fmt.format(sideeffect=sideeffect, asm=self.asm,
constraint=self.constraint))
def get_reference(self):
buf = []
self.descr(buf)
return "".join(buf)
def __str__(self):
return "{0} {1}".format(self.type, self.get_reference())
class AtomicRMW(Instruction):
def __init__(self, parent, op, ptr, val, ordering, name):
super(AtomicRMW, self).__init__(parent, val.type, "atomicrmw",
(ptr, val), name=name)
self.operation = op
self.ordering = ordering
def descr(self, buf):
ptr, val = self.operands
fmt = ("atomicrmw {op} {ptrty} {ptr}, {valty} {val} {ordering} "
"{metadata}\n")
buf.append(fmt.format(op=self.operation,
ptrty=ptr.type,
ptr=ptr.get_reference(),
valty=val.type,
val=val.get_reference(),
ordering=self.ordering,
metadata=self._stringify_metadata(
leading_comma=True),
))
class CmpXchg(Instruction):
"""This instruction has changed since llvm3.5. It is not compatible with
older llvm versions.
"""
def __init__(self, parent, ptr, cmp, val, ordering, failordering, name):
outtype = types.LiteralStructType([val.type, types.IntType(1)])
super(CmpXchg, self).__init__(parent, outtype, "cmpxchg",
(ptr, cmp, val), name=name)
self.ordering = ordering
self.failordering = failordering
def descr(self, buf):
ptr, cmpval, val = self.operands
fmt = "cmpxchg {ptrty} {ptr}, {ty} {cmp}, {ty} {val} {ordering} " \
"{failordering} {metadata}\n"
buf.append(fmt.format(ptrty=ptr.type,
ptr=ptr.get_reference(),
ty=cmpval.type,
cmp=cmpval.get_reference(),
val=val.get_reference(),
ordering=self.ordering,
failordering=self.failordering,
metadata=self._stringify_metadata(
leading_comma=True),
))
class _LandingPadClause(object):
def __init__(self, value):
self.value = value
def __str__(self):
return "{kind} {type} {value}".format(
kind=self.kind,
type=self.value.type,
value=self.value.get_reference())
class CatchClause(_LandingPadClause):
kind = 'catch'
class FilterClause(_LandingPadClause):
kind = 'filter'
def __init__(self, value):
assert isinstance(value, Constant)
assert isinstance(value.type, types.ArrayType)
super(FilterClause, self).__init__(value)
class LandingPadInstr(Instruction):
def __init__(self, parent, typ, name='', cleanup=False):
super(LandingPadInstr, self).__init__(parent, typ, "landingpad", [],
name=name)
self.cleanup = cleanup
self.clauses = []
def add_clause(self, clause):
assert isinstance(clause, _LandingPadClause)
self.clauses.append(clause)
def descr(self, buf):
fmt = "landingpad {type}{cleanup}{clauses}\n"
buf.append(fmt.format(type=self.type,
cleanup=' cleanup' if self.cleanup else '',
clauses=''.join(["\n {0}".format(clause)
for clause in self.clauses]),
))
class Fence(Instruction):
"""
The `fence` instruction.
As of LLVM 5.0.1:
fence [syncscope("<target-scope>")] <ordering> ; yields void
"""
VALID_FENCE_ORDERINGS = {"acquire", "release", "acq_rel", "seq_cst"}
def __init__(self, parent, ordering, targetscope=None, name=''):
super(Fence, self).__init__(parent, types.VoidType(), "fence", (),
name=name)
if ordering not in self.VALID_FENCE_ORDERINGS:
msg = "Invalid fence ordering \"{0}\"! Should be one of {1}."
raise ValueError(msg .format(ordering,
", ".join(self.VALID_FENCE_ORDERINGS)))
self.ordering = ordering
self.targetscope = targetscope
def descr(self, buf):
if self.targetscope is None:
syncscope = ""
else:
syncscope = 'syncscope("{0}") '.format(self.targetscope)
fmt = "fence {syncscope}{ordering}\n"
buf.append(fmt.format(syncscope=syncscope,
ordering=self.ordering,
))
class Comment(Instruction):
"""
A line comment.
"""
def __init__(self, parent, text):
super(Comment, self).__init__(parent, types.VoidType(), ";", (),
name='')
assert "\n" not in text, "Comment cannot contain new line"
self.text = text
def descr(self, buf):
buf.append(f"; {self.text}")