forked from M-Labs/artiq
compiler, firmware: use Pascal strings everywhere.
This removes a large amount of very ugly code, and also simplifies the compiler and runtime.
This commit is contained in:
parent
e13d8919ff
commit
fd8b11532f
|
@ -36,13 +36,6 @@ class TKeyword(types.TMono):
|
||||||
def is_keyword(typ):
|
def is_keyword(typ):
|
||||||
return isinstance(typ, TKeyword)
|
return isinstance(typ, TKeyword)
|
||||||
|
|
||||||
class TExceptionTypeInfo(types.TMono):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__("exntypeinfo")
|
|
||||||
|
|
||||||
def is_exn_typeinfo(typ):
|
|
||||||
return isinstance(typ, TExceptionTypeInfo)
|
|
||||||
|
|
||||||
class Value:
|
class Value:
|
||||||
"""
|
"""
|
||||||
An SSA value that keeps track of its uses.
|
An SSA value that keeps track of its uses.
|
||||||
|
|
|
@ -1332,10 +1332,6 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
rhs_length = self.iterable_len(rhs)
|
rhs_length = self.iterable_len(rhs)
|
||||||
|
|
||||||
result_length = self.append(ir.Arith(ast.Add(loc=None), lhs_length, rhs_length))
|
result_length = self.append(ir.Arith(ast.Add(loc=None), lhs_length, rhs_length))
|
||||||
if builtins.is_str(node.left.type):
|
|
||||||
result_last = result_length
|
|
||||||
result_length = self.append(ir.Arith(ast.Add(loc=None), result_length,
|
|
||||||
ir.Constant(1, self._size_type)))
|
|
||||||
result = self.append(ir.Alloc([result_length], node.type))
|
result = self.append(ir.Alloc([result_length], node.type))
|
||||||
|
|
||||||
# Copy lhs
|
# Copy lhs
|
||||||
|
@ -1359,10 +1355,6 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, rhs_length)),
|
lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, rhs_length)),
|
||||||
body_gen)
|
body_gen)
|
||||||
|
|
||||||
if builtins.is_str(node.left.type):
|
|
||||||
self.append(ir.SetElem(result, result_last,
|
|
||||||
ir.Constant(0, builtins.TInt(types.TValue(8)))))
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
@ -1564,13 +1556,13 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
# Keep this function with builtins.TException.attributes.
|
# Keep this function with builtins.TException.attributes.
|
||||||
def alloc_exn(self, typ, message=None, param0=None, param1=None, param2=None):
|
def alloc_exn(self, typ, message=None, param0=None, param1=None, param2=None):
|
||||||
typ = typ.find()
|
typ = typ.find()
|
||||||
|
name = "{}:{}".format(typ.id, typ.name)
|
||||||
attributes = [
|
attributes = [
|
||||||
ir.Constant("{}:{}".format(typ.id, typ.name),
|
ir.Constant(name, builtins.TStr()), # typeinfo
|
||||||
ir.TExceptionTypeInfo()), # typeinfo
|
ir.Constant("<not thrown>", builtins.TStr()), # file
|
||||||
ir.Constant("<not thrown>", builtins.TStr()), # file
|
ir.Constant(0, builtins.TInt32()), # line
|
||||||
ir.Constant(0, builtins.TInt32()), # line
|
ir.Constant(0, builtins.TInt32()), # column
|
||||||
ir.Constant(0, builtins.TInt32()), # column
|
ir.Constant("<not thrown>", builtins.TStr()), # function
|
||||||
ir.Constant("<not thrown>", builtins.TStr()), # function
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if message is None:
|
if message is None:
|
||||||
|
@ -1892,7 +1884,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
else:
|
else:
|
||||||
explanation = node.loc.source()
|
explanation = node.loc.source()
|
||||||
self.append(ir.Builtin("printf", [
|
self.append(ir.Builtin("printf", [
|
||||||
ir.Constant("assertion failed at %s: %s\n", builtins.TStr()),
|
ir.Constant("assertion failed at %.*s: %.*s\n\x00", builtins.TStr()),
|
||||||
ir.Constant(str(node.loc.begin()), builtins.TStr()),
|
ir.Constant(str(node.loc.begin()), builtins.TStr()),
|
||||||
ir.Constant(str(explanation), builtins.TStr()),
|
ir.Constant(str(explanation), builtins.TStr()),
|
||||||
], builtins.TNone()))
|
], builtins.TNone()))
|
||||||
|
@ -1905,7 +1897,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
|
|
||||||
subexpr_body = self.current_block = self.add_block("assert.subexpr.body")
|
subexpr_body = self.current_block = self.add_block("assert.subexpr.body")
|
||||||
self.append(ir.Builtin("printf", [
|
self.append(ir.Builtin("printf", [
|
||||||
ir.Constant(" (%s) = ", builtins.TStr()),
|
ir.Constant(" (%.*s) = \x00", builtins.TStr()),
|
||||||
ir.Constant(subexpr_node.loc.source(), builtins.TStr())
|
ir.Constant(subexpr_node.loc.source(), builtins.TStr())
|
||||||
], builtins.TNone()))
|
], builtins.TNone()))
|
||||||
subexpr_value = self.append(ir.Builtin("unwrap", [subexpr_value_opt],
|
subexpr_value = self.append(ir.Builtin("unwrap", [subexpr_value_opt],
|
||||||
|
@ -1937,7 +1929,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
def flush():
|
def flush():
|
||||||
nonlocal format_string, args
|
nonlocal format_string, args
|
||||||
if format_string != "":
|
if format_string != "":
|
||||||
printf(format_string, *args)
|
printf(format_string + "\x00", *args)
|
||||||
format_string = ""
|
format_string = ""
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
|
@ -1961,7 +1953,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
elif builtins.is_none(value.type):
|
elif builtins.is_none(value.type):
|
||||||
format_string += "None"
|
format_string += "None"
|
||||||
elif builtins.is_bool(value.type):
|
elif builtins.is_bool(value.type):
|
||||||
format_string += "%s"
|
format_string += "%.*s"
|
||||||
args.append(self.append(ir.Select(value,
|
args.append(self.append(ir.Select(value,
|
||||||
ir.Constant("True", builtins.TStr()),
|
ir.Constant("True", builtins.TStr()),
|
||||||
ir.Constant("False", builtins.TStr()))))
|
ir.Constant("False", builtins.TStr()))))
|
||||||
|
@ -1979,9 +1971,9 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
args.append(value)
|
args.append(value)
|
||||||
elif builtins.is_str(value.type):
|
elif builtins.is_str(value.type):
|
||||||
if as_repr:
|
if as_repr:
|
||||||
format_string += "\"%s\""
|
format_string += "\"%.*s\""
|
||||||
else:
|
else:
|
||||||
format_string += "%s"
|
format_string += "%.*s"
|
||||||
args.append(value)
|
args.append(value)
|
||||||
elif builtins.is_listish(value.type):
|
elif builtins.is_listish(value.type):
|
||||||
if builtins.is_list(value.type):
|
if builtins.is_list(value.type):
|
||||||
|
@ -2000,7 +1992,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
head = self.current_block
|
head = self.current_block
|
||||||
|
|
||||||
if_last = self.current_block = self.add_block("print.comma")
|
if_last = self.current_block = self.add_block("print.comma")
|
||||||
printf(", ")
|
printf(", \x00")
|
||||||
|
|
||||||
tail = self.current_block = self.add_block("print.tail")
|
tail = self.current_block = self.add_block("print.tail")
|
||||||
if_last.append(ir.Branch(tail))
|
if_last.append(ir.Branch(tail))
|
||||||
|
@ -2032,7 +2024,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
param2 = self.append(ir.GetAttr(value, "__param1__"))
|
param2 = self.append(ir.GetAttr(value, "__param1__"))
|
||||||
param3 = self.append(ir.GetAttr(value, "__param2__"))
|
param3 = self.append(ir.GetAttr(value, "__param2__"))
|
||||||
|
|
||||||
format_string += "%s(%s, %lld, %lld, %lld)"
|
format_string += "%.*s(%.*s, %lld, %lld, %lld)"
|
||||||
args += [name, message, param1, param2, param3]
|
args += [name, message, param1, param2, param3]
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
|
@ -20,6 +20,8 @@ lli64 = ll.IntType(64)
|
||||||
lldouble = ll.DoubleType()
|
lldouble = ll.DoubleType()
|
||||||
llptr = ll.IntType(8).as_pointer()
|
llptr = ll.IntType(8).as_pointer()
|
||||||
llptrptr = ll.IntType(8).as_pointer().as_pointer()
|
llptrptr = ll.IntType(8).as_pointer().as_pointer()
|
||||||
|
llslice = ll.LiteralStructType([llptr, lli32])
|
||||||
|
llsliceptr = ll.LiteralStructType([llptr, lli32]).as_pointer()
|
||||||
llmetadata = ll.MetaData()
|
llmetadata = ll.MetaData()
|
||||||
|
|
||||||
|
|
||||||
|
@ -216,8 +218,6 @@ class LLVMIRGenerator:
|
||||||
return ll.IntType(builtins.get_int_width(typ))
|
return ll.IntType(builtins.get_int_width(typ))
|
||||||
elif builtins.is_float(typ):
|
elif builtins.is_float(typ):
|
||||||
return lldouble
|
return lldouble
|
||||||
elif builtins.is_str(typ) or ir.is_exn_typeinfo(typ):
|
|
||||||
return llptr
|
|
||||||
elif builtins.is_listish(typ):
|
elif builtins.is_listish(typ):
|
||||||
lleltty = self.llty_of_type(builtins.get_iterable_elt(typ))
|
lleltty = self.llty_of_type(builtins.get_iterable_elt(typ))
|
||||||
return ll.LiteralStructType([lleltty.as_pointer(), lli32])
|
return ll.LiteralStructType([lleltty.as_pointer(), lli32])
|
||||||
|
@ -229,7 +229,7 @@ class LLVMIRGenerator:
|
||||||
elif ir.is_option(typ):
|
elif ir.is_option(typ):
|
||||||
return ll.LiteralStructType([lli1, self.llty_of_type(typ.params["value"])])
|
return ll.LiteralStructType([lli1, self.llty_of_type(typ.params["value"])])
|
||||||
elif ir.is_keyword(typ):
|
elif ir.is_keyword(typ):
|
||||||
return ll.LiteralStructType([llptr, self.llty_of_type(typ.params["value"])])
|
return ll.LiteralStructType([llslice, self.llty_of_type(typ.params["value"])])
|
||||||
elif ir.is_environment(typ):
|
elif ir.is_environment(typ):
|
||||||
llty = self.llcontext.get_identified_type("env.{}".format(typ.env_name))
|
llty = self.llcontext.get_identified_type("env.{}".format(typ.env_name))
|
||||||
if llty.elements is None:
|
if llty.elements is None:
|
||||||
|
@ -262,8 +262,7 @@ class LLVMIRGenerator:
|
||||||
|
|
||||||
def llstr_of_str(self, value, name=None, linkage="private", unnamed_addr=True):
|
def llstr_of_str(self, value, name=None, linkage="private", unnamed_addr=True):
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
assert "\0" not in value
|
as_bytes = value.encode("utf-8")
|
||||||
as_bytes = (value + "\0").encode("utf-8")
|
|
||||||
else:
|
else:
|
||||||
as_bytes = value
|
as_bytes = value
|
||||||
|
|
||||||
|
@ -295,19 +294,14 @@ class LLVMIRGenerator:
|
||||||
elif isinstance(const.value, (int, float)):
|
elif isinstance(const.value, (int, float)):
|
||||||
return ll.Constant(llty, const.value)
|
return ll.Constant(llty, const.value)
|
||||||
elif isinstance(const.value, (str, bytes)):
|
elif isinstance(const.value, (str, bytes)):
|
||||||
if ir.is_exn_typeinfo(const.type):
|
if isinstance(const.value, str):
|
||||||
# Exception typeinfo; should be merged with identical others
|
value = const.value.encode('utf-8')
|
||||||
name = "__artiq_exn_" + const.value
|
|
||||||
linkage = "linkonce"
|
|
||||||
unnamed_addr = False
|
|
||||||
else:
|
else:
|
||||||
# Just a string
|
value = const.value
|
||||||
name = None
|
|
||||||
linkage = "private"
|
|
||||||
unnamed_addr = True
|
|
||||||
|
|
||||||
return self.llstr_of_str(const.value, name=name,
|
llptr = self.llstr_of_str(const.value, linkage="private", unnamed_addr=True)
|
||||||
linkage=linkage, unnamed_addr=unnamed_addr)
|
lllen = ll.Constant(lli32, len(const.value))
|
||||||
|
return ll.Constant(llty, (llptr, lllen))
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
@ -318,8 +312,6 @@ class LLVMIRGenerator:
|
||||||
|
|
||||||
if name in "llvm.donothing":
|
if name in "llvm.donothing":
|
||||||
llty = ll.FunctionType(llvoid, [])
|
llty = ll.FunctionType(llvoid, [])
|
||||||
elif name in "llvm.trap":
|
|
||||||
llty = ll.FunctionType(llvoid, [])
|
|
||||||
elif name == "llvm.floor.f64":
|
elif name == "llvm.floor.f64":
|
||||||
llty = ll.FunctionType(lldouble, [lldouble])
|
llty = ll.FunctionType(lldouble, [lldouble])
|
||||||
elif name == "llvm.round.f64":
|
elif name == "llvm.round.f64":
|
||||||
|
@ -344,14 +336,14 @@ class LLVMIRGenerator:
|
||||||
llty = ll.FunctionType(llvoid, [self.llty_of_type(builtins.TException())])
|
llty = ll.FunctionType(llvoid, [self.llty_of_type(builtins.TException())])
|
||||||
elif name == "__artiq_reraise":
|
elif name == "__artiq_reraise":
|
||||||
llty = ll.FunctionType(llvoid, [])
|
llty = ll.FunctionType(llvoid, [])
|
||||||
elif name == "strlen":
|
elif name in "abort":
|
||||||
llty = ll.FunctionType(lli32, [llptr])
|
llty = ll.FunctionType(llvoid, [])
|
||||||
elif name == "strcmp":
|
elif name == "memcmp":
|
||||||
llty = ll.FunctionType(lli32, [llptr, llptr])
|
llty = ll.FunctionType(lli32, [llptr, llptr, lli32])
|
||||||
elif name == "send_rpc":
|
elif name == "send_rpc":
|
||||||
llty = ll.FunctionType(llvoid, [lli32, llptr, llptrptr])
|
llty = ll.FunctionType(llvoid, [lli32, llsliceptr, llptrptr])
|
||||||
elif name == "send_async_rpc":
|
elif name == "send_async_rpc":
|
||||||
llty = ll.FunctionType(llvoid, [lli32, llptr, llptrptr])
|
llty = ll.FunctionType(llvoid, [lli32, llsliceptr, llptrptr])
|
||||||
elif name == "recv_rpc":
|
elif name == "recv_rpc":
|
||||||
llty = ll.FunctionType(lli32, [llptr])
|
llty = ll.FunctionType(lli32, [llptr])
|
||||||
elif name == "now":
|
elif name == "now":
|
||||||
|
@ -423,7 +415,7 @@ class LLVMIRGenerator:
|
||||||
llobjects[obj_typ].append(llobject.bitcast(llptr))
|
llobjects[obj_typ].append(llobject.bitcast(llptr))
|
||||||
|
|
||||||
llrpcattrty = self.llcontext.get_identified_type("A")
|
llrpcattrty = self.llcontext.get_identified_type("A")
|
||||||
llrpcattrty.elements = [lli32, llptr, llptr]
|
llrpcattrty.elements = [lli32, llslice, llslice]
|
||||||
|
|
||||||
lldescty = self.llcontext.get_identified_type("D")
|
lldescty = self.llcontext.get_identified_type("D")
|
||||||
lldescty.elements = [llrpcattrty.as_pointer().as_pointer(), llptr.as_pointer()]
|
lldescty.elements = [llrpcattrty.as_pointer().as_pointer(), llptr.as_pointer()]
|
||||||
|
@ -445,15 +437,14 @@ class LLVMIRGenerator:
|
||||||
|
|
||||||
if not (types.is_function(typ) or types.is_method(typ) or types.is_rpc(typ) or
|
if not (types.is_function(typ) or types.is_method(typ) or types.is_rpc(typ) or
|
||||||
name == "__objectid__"):
|
name == "__objectid__"):
|
||||||
rpctag = b"Os" + self._rpc_tag(typ, error_handler=rpc_tag_error) + b":n\x00"
|
rpctag = b"Os" + self._rpc_tag(typ, error_handler=rpc_tag_error) + b":n"
|
||||||
llrpctag = self.llstr_of_str(rpctag)
|
|
||||||
else:
|
else:
|
||||||
llrpctag = ll.Constant(llptr, None)
|
rpctag = b""
|
||||||
|
|
||||||
llrpcattrinit = ll.Constant(llrpcattrty, [
|
llrpcattrinit = ll.Constant(llrpcattrty, [
|
||||||
ll.Constant(lli32, offset),
|
ll.Constant(lli32, offset),
|
||||||
llrpctag,
|
self.llconst_of_const(ir.Constant(rpctag, builtins.TStr())),
|
||||||
self.llstr_of_str(name)
|
self.llconst_of_const(ir.Constant(name, builtins.TStr()))
|
||||||
])
|
])
|
||||||
|
|
||||||
if name == "__objectid__":
|
if name == "__objectid__":
|
||||||
|
@ -615,10 +606,6 @@ class LLVMIRGenerator:
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
elif builtins.is_str(insn.type):
|
|
||||||
llsize = self.map(insn.operands[0])
|
|
||||||
llvalue = self.llbuilder.alloca(lli8, size=llsize)
|
|
||||||
return llvalue
|
|
||||||
elif builtins.is_listish(insn.type):
|
elif builtins.is_listish(insn.type):
|
||||||
llsize = self.map(insn.operands[0])
|
llsize = self.map(insn.operands[0])
|
||||||
lleltty = self.llty_of_type(builtins.get_iterable_elt(insn.type))
|
lleltty = self.llty_of_type(builtins.get_iterable_elt(insn.type))
|
||||||
|
@ -829,13 +816,9 @@ class LLVMIRGenerator:
|
||||||
def process_GetElem(self, insn):
|
def process_GetElem(self, insn):
|
||||||
lst, idx = insn.list(), insn.index()
|
lst, idx = insn.list(), insn.index()
|
||||||
lllst, llidx = map(self.map, (lst, idx))
|
lllst, llidx = map(self.map, (lst, idx))
|
||||||
if builtins.is_str(lst.type):
|
llelts = self.llbuilder.extract_value(lllst, 0)
|
||||||
llelt = self.llbuilder.gep(lllst, [llidx], inbounds=True)
|
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
|
||||||
llvalue = self.llbuilder.load(llelt)
|
llvalue = self.llbuilder.load(llelt)
|
||||||
else:
|
|
||||||
llelts = self.llbuilder.extract_value(lllst, 0)
|
|
||||||
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
|
|
||||||
llvalue = self.llbuilder.load(llelt)
|
|
||||||
if isinstance(llvalue.type, ll.PointerType):
|
if isinstance(llvalue.type, ll.PointerType):
|
||||||
self.mark_dereferenceable(llvalue)
|
self.mark_dereferenceable(llvalue)
|
||||||
return llvalue
|
return llvalue
|
||||||
|
@ -843,11 +826,8 @@ class LLVMIRGenerator:
|
||||||
def process_SetElem(self, insn):
|
def process_SetElem(self, insn):
|
||||||
lst, idx = insn.list(), insn.index()
|
lst, idx = insn.list(), insn.index()
|
||||||
lllst, llidx = map(self.map, (lst, idx))
|
lllst, llidx = map(self.map, (lst, idx))
|
||||||
if builtins.is_str(lst.type):
|
llelts = self.llbuilder.extract_value(lllst, 0)
|
||||||
llelt = self.llbuilder.gep(lllst, [llidx], inbounds=True)
|
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
|
||||||
else:
|
|
||||||
llelts = self.llbuilder.extract_value(lllst, 0)
|
|
||||||
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
|
|
||||||
return self.llbuilder.store(self.map(insn.value()), llelt)
|
return self.llbuilder.store(self.map(insn.value()), llelt)
|
||||||
|
|
||||||
def process_Coerce(self, insn):
|
def process_Coerce(self, insn):
|
||||||
|
@ -1029,7 +1009,7 @@ class LLVMIRGenerator:
|
||||||
if insn.op == "nop":
|
if insn.op == "nop":
|
||||||
return self.llbuilder.call(self.llbuiltin("llvm.donothing"), [])
|
return self.llbuilder.call(self.llbuiltin("llvm.donothing"), [])
|
||||||
if insn.op == "abort":
|
if insn.op == "abort":
|
||||||
return self.llbuilder.call(self.llbuiltin("llvm.trap"), [])
|
return self.llbuilder.call(self.llbuiltin("abort"), [])
|
||||||
elif insn.op == "is_some":
|
elif insn.op == "is_some":
|
||||||
lloptarg = self.map(insn.operands[0])
|
lloptarg = self.map(insn.operands[0])
|
||||||
return self.llbuilder.extract_value(lloptarg, 0,
|
return self.llbuilder.extract_value(lloptarg, 0,
|
||||||
|
@ -1066,15 +1046,21 @@ class LLVMIRGenerator:
|
||||||
return get_outer(self.map(env), env.type)
|
return get_outer(self.map(env), env.type)
|
||||||
elif insn.op == "len":
|
elif insn.op == "len":
|
||||||
collection, = insn.operands
|
collection, = insn.operands
|
||||||
if builtins.is_str(collection.type):
|
return self.llbuilder.extract_value(self.map(collection), 1)
|
||||||
return self.llbuilder.call(self.llbuiltin("strlen"), [self.map(collection)])
|
|
||||||
else:
|
|
||||||
return self.llbuilder.extract_value(self.map(collection), 1)
|
|
||||||
elif insn.op in ("printf", "rtio_log"):
|
elif insn.op in ("printf", "rtio_log"):
|
||||||
# We only get integers, floats, pointers and strings here.
|
# We only get integers, floats, pointers and strings here.
|
||||||
llargs = map(self.map, insn.operands)
|
lloperands = []
|
||||||
|
for i, operand in enumerate(insn.operands):
|
||||||
|
lloperand = self.map(operand)
|
||||||
|
if i == 0 and insn.op == "printf" or i == 1 and insn.op == "rtio_log":
|
||||||
|
lloperands.append(self.llbuilder.extract_value(lloperand, 0))
|
||||||
|
elif builtins.is_str(operand.type):
|
||||||
|
lloperands.append(self.llbuilder.extract_value(lloperand, 1))
|
||||||
|
lloperands.append(self.llbuilder.extract_value(lloperand, 0))
|
||||||
|
else:
|
||||||
|
lloperands.append(lloperand)
|
||||||
func_name = self.target.print_function if insn.op == "printf" else insn.op
|
func_name = self.target.print_function if insn.op == "printf" else insn.op
|
||||||
return self.llbuilder.call(self.llbuiltin(func_name), llargs,
|
return self.llbuilder.call(self.llbuiltin(func_name), lloperands,
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
elif insn.op == "exncast":
|
elif insn.op == "exncast":
|
||||||
# This is an identity cast at LLVM IR level.
|
# This is an identity cast at LLVM IR level.
|
||||||
|
@ -1231,9 +1217,10 @@ class LLVMIRGenerator:
|
||||||
fun_loc)
|
fun_loc)
|
||||||
self.engine.process(diag)
|
self.engine.process(diag)
|
||||||
tag += self._rpc_tag(fun_type.ret, ret_error_handler)
|
tag += self._rpc_tag(fun_type.ret, ret_error_handler)
|
||||||
tag += b"\x00"
|
|
||||||
|
|
||||||
lltag = self.llstr_of_str(tag)
|
lltag = self.llconst_of_const(ir.Constant(tag, builtins.TStr()))
|
||||||
|
lltagptr = self.llbuilder.alloca(lltag.type)
|
||||||
|
self.llbuilder.store(lltag, lltagptr)
|
||||||
|
|
||||||
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [],
|
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [],
|
||||||
name="rpc.stack")
|
name="rpc.stack")
|
||||||
|
@ -1256,10 +1243,10 @@ class LLVMIRGenerator:
|
||||||
|
|
||||||
if fun_type.async:
|
if fun_type.async:
|
||||||
self.llbuilder.call(self.llbuiltin("send_async_rpc"),
|
self.llbuilder.call(self.llbuiltin("send_async_rpc"),
|
||||||
[llservice, lltag, llargs])
|
[llservice, lltagptr, llargs])
|
||||||
else:
|
else:
|
||||||
self.llbuilder.call(self.llbuiltin("send_rpc"),
|
self.llbuilder.call(self.llbuiltin("send_rpc"),
|
||||||
[llservice, lltag, llargs])
|
[llservice, lltagptr, llargs])
|
||||||
|
|
||||||
# Don't waste stack space on saved arguments.
|
# Don't waste stack space on saved arguments.
|
||||||
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
||||||
|
@ -1446,19 +1433,16 @@ class LLVMIRGenerator:
|
||||||
elif builtins.is_float(typ):
|
elif builtins.is_float(typ):
|
||||||
assert isinstance(value, float)
|
assert isinstance(value, float)
|
||||||
return ll.Constant(llty, value)
|
return ll.Constant(llty, value)
|
||||||
elif builtins.is_str(typ):
|
|
||||||
assert isinstance(value, (str, bytes))
|
|
||||||
return self.llstr_of_str(value)
|
|
||||||
elif builtins.is_listish(typ):
|
elif builtins.is_listish(typ):
|
||||||
assert isinstance(value, (list, numpy.ndarray))
|
assert isinstance(value, (str, bytes, list, numpy.ndarray))
|
||||||
elt_type = builtins.get_iterable_elt(typ)
|
elt_type = builtins.get_iterable_elt(typ)
|
||||||
llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)])
|
llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)])
|
||||||
for i in range(len(value))]
|
for i in range(len(value))]
|
||||||
lleltsary = ll.Constant(ll.ArrayType(self.llty_of_type(elt_type), len(llelts)),
|
lleltsary = ll.Constant(ll.ArrayType(self.llty_of_type(elt_type), len(llelts)),
|
||||||
list(llelts))
|
list(llelts))
|
||||||
|
|
||||||
llglobal = ll.GlobalVariable(self.llmodule, lleltsary.type,
|
name = self.llmodule.scope.deduplicate("quoted.{}".format(typ.name))
|
||||||
self.llmodule.scope.deduplicate("quoted.list"))
|
llglobal = ll.GlobalVariable(self.llmodule, lleltsary.type, name)
|
||||||
llglobal.initializer = lleltsary
|
llglobal.initializer = lleltsary
|
||||||
llglobal.linkage = "private"
|
llglobal.linkage = "private"
|
||||||
|
|
||||||
|
@ -1556,23 +1540,38 @@ class LLVMIRGenerator:
|
||||||
|
|
||||||
for target, typ in insn.clauses():
|
for target, typ in insn.clauses():
|
||||||
if typ is None:
|
if typ is None:
|
||||||
llclauseexnname = ll.Constant(
|
llclauseexnnameptr = ll.Constant(
|
||||||
self.llty_of_type(ir.TExceptionTypeInfo()), None)
|
self.llty_of_type(builtins.TStr()).as_pointer(), None)
|
||||||
else:
|
else:
|
||||||
|
exnname = "{}:{}".format(typ.id, typ.name)
|
||||||
llclauseexnname = self.llconst_of_const(
|
llclauseexnname = self.llconst_of_const(
|
||||||
ir.Constant("{}:{}".format(typ.id, typ.name),
|
ir.Constant(exnname, builtins.TStr()))
|
||||||
ir.TExceptionTypeInfo()))
|
|
||||||
lllandingpad.add_clause(ll.CatchClause(llclauseexnname))
|
llclauseexnnameptr = self.llmodule.get_global("exn.{}".format(exnname))
|
||||||
|
if llclauseexnnameptr is None:
|
||||||
|
llclauseexnnameptr = ll.GlobalVariable(self.llmodule, llclauseexnname.type,
|
||||||
|
name="exn.{}".format(exnname))
|
||||||
|
llclauseexnnameptr.global_constant = True
|
||||||
|
llclauseexnnameptr.initializer = llclauseexnname
|
||||||
|
llclauseexnnameptr.linkage = "private"
|
||||||
|
llclauseexnnameptr.unnamed_addr = True
|
||||||
|
lllandingpad.add_clause(ll.CatchClause(llclauseexnnameptr))
|
||||||
|
|
||||||
if typ is None:
|
if typ is None:
|
||||||
self.llbuilder.branch(self.map(target))
|
self.llbuilder.branch(self.map(target))
|
||||||
else:
|
else:
|
||||||
llexnmatch = self.llbuilder.call(self.llbuiltin("strcmp"),
|
llexnlen = self.llbuilder.extract_value(llexnname, 1)
|
||||||
[llexnname, llclauseexnname])
|
llclauseexnlen = self.llbuilder.extract_value(llclauseexnname, 1)
|
||||||
llmatchingclause = self.llbuilder.icmp_unsigned('==',
|
llmatchinglen = self.llbuilder.icmp_unsigned('==', llexnlen, llclauseexnlen)
|
||||||
llexnmatch, ll.Constant(lli32, 0))
|
with self.llbuilder.if_then(llmatchinglen):
|
||||||
with self.llbuilder.if_then(llmatchingclause):
|
llexnptr = self.llbuilder.extract_value(llexnname, 0)
|
||||||
self.llbuilder.branch(self.map(target))
|
llclauseexnptr = self.llbuilder.extract_value(llclauseexnname, 0)
|
||||||
|
llcomparedata = self.llbuilder.call(self.llbuiltin("memcmp"),
|
||||||
|
[llexnptr, llclauseexnptr, llexnlen])
|
||||||
|
llmatchingdata = self.llbuilder.icmp_unsigned('==', llcomparedata,
|
||||||
|
ll.Constant(lli32, 0))
|
||||||
|
with self.llbuilder.if_then(llmatchingdata):
|
||||||
|
self.llbuilder.branch(self.map(target))
|
||||||
|
|
||||||
if self.llbuilder.basic_block.terminator is None:
|
if self.llbuilder.basic_block.terminator is None:
|
||||||
self.llbuilder.branch(self.map(insn.cleanup()))
|
self.llbuilder.branch(self.map(insn.cleanup()))
|
||||||
|
|
|
@ -115,6 +115,7 @@ dependencies = [
|
||||||
"build_artiq 0.0.0",
|
"build_artiq 0.0.0",
|
||||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins)",
|
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins)",
|
||||||
|
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fringe 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fringe 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"logger_artiq 0.0.0",
|
"logger_artiq 0.0.0",
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use libc::{c_void, c_char, size_t};
|
|
||||||
|
|
||||||
macro_rules! api {
|
macro_rules! api {
|
||||||
($i:ident) => ({
|
($i:ident) => ({
|
||||||
extern { static $i: c_void; }
|
extern { static $i: u8; }
|
||||||
api!($i = &$i as *const _)
|
api!($i = &$i as *const _)
|
||||||
});
|
});
|
||||||
($i:ident, $d:item) => ({
|
($i:ident, $d:item) => ({
|
||||||
|
@ -68,9 +66,8 @@ static mut API: &'static [(&'static str, *const ())] = &[
|
||||||
api!(__powidf2),
|
api!(__powidf2),
|
||||||
|
|
||||||
/* libc */
|
/* libc */
|
||||||
api!(strcmp),
|
|
||||||
api!(strlen, extern { fn strlen(s: *const c_char) -> size_t; }),
|
|
||||||
api!(abort = ::abort),
|
api!(abort = ::abort),
|
||||||
|
api!(memcmp, extern { fn memcmp(a: *const u8, b: *mut u8, size: usize); }),
|
||||||
|
|
||||||
/* libm */
|
/* libm */
|
||||||
api!(sqrt),
|
api!(sqrt),
|
||||||
|
|
|
@ -30,15 +30,14 @@ extern {
|
||||||
macro_rules! artiq_raise {
|
macro_rules! artiq_raise {
|
||||||
($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => ({
|
($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => ({
|
||||||
let exn = $crate::kernel_proto::Exception {
|
let exn = $crate::kernel_proto::Exception {
|
||||||
name: concat!("0:artiq.coredevice.exceptions.", $name, "\0").as_bytes().as_ptr(),
|
name: concat!("0:artiq.coredevice.exceptions.", $name),
|
||||||
file: concat!(file!(), "\0").as_bytes().as_ptr(),
|
file: file!(),
|
||||||
line: line!(),
|
line: line!(),
|
||||||
column: column!(),
|
column: column!(),
|
||||||
// https://github.com/rust-lang/rfcs/pull/1719
|
// https://github.com/rust-lang/rfcs/pull/1719
|
||||||
function: "(Rust function)\0".as_bytes().as_ptr(),
|
function: "(Rust function)",
|
||||||
message: concat!($message, "\0").as_bytes().as_ptr(),
|
message: $message,
|
||||||
param: [$param0, $param1, $param2],
|
param: [$param0, $param1, $param2]
|
||||||
phantom: ::core::marker::PhantomData
|
|
||||||
};
|
};
|
||||||
#[allow(unused_unsafe)]
|
#[allow(unused_unsafe)]
|
||||||
unsafe { $crate::__artiq_raise(&exn as *const _) }
|
unsafe { $crate::__artiq_raise(&exn as *const _) }
|
||||||
|
@ -48,9 +47,8 @@ macro_rules! artiq_raise {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
use core::{mem, ptr, slice, str};
|
use core::{mem, ptr, str};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use libc::{c_char, size_t};
|
|
||||||
use cslice::{CSlice, CMutSlice, AsCSlice};
|
use cslice::{CSlice, CMutSlice, AsCSlice};
|
||||||
use kernel_proto::*;
|
use kernel_proto::*;
|
||||||
use dyld::Library;
|
use dyld::Library;
|
||||||
|
@ -125,28 +123,22 @@ extern fn abort() -> ! {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn send_rpc(service: u32, tag: *const u8, data: *const *const ()) {
|
extern fn send_rpc(service: u32, tag: CSlice<u8>, data: *const *const ()) {
|
||||||
extern { fn strlen(s: *const c_char) -> size_t; }
|
|
||||||
let tag = unsafe { slice::from_raw_parts(tag, strlen(tag as *const c_char)) };
|
|
||||||
|
|
||||||
while !rpc_queue::empty() {}
|
while !rpc_queue::empty() {}
|
||||||
send(&RpcSend {
|
send(&RpcSend {
|
||||||
async: false,
|
async: false,
|
||||||
service: service,
|
service: service,
|
||||||
tag: tag,
|
tag: tag.as_ref(),
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn send_async_rpc(service: u32, tag: *const u8, data: *const *const ()) {
|
extern fn send_async_rpc(service: u32, tag: CSlice<u8>, data: *const *const ()) {
|
||||||
extern { fn strlen(s: *const c_char) -> size_t; }
|
|
||||||
let tag = unsafe { slice::from_raw_parts(tag, strlen(tag as *const c_char)) };
|
|
||||||
|
|
||||||
while rpc_queue::full() {}
|
while rpc_queue::full() {}
|
||||||
rpc_queue::enqueue(|mut slice| {
|
rpc_queue::enqueue(|mut slice| {
|
||||||
let length = {
|
let length = {
|
||||||
let mut writer = Cursor::new(&mut slice[4..]);
|
let mut writer = Cursor::new(&mut slice[4..]);
|
||||||
rpc_proto::send_args(&mut writer, service, tag, data)?;
|
rpc_proto::send_args(&mut writer, service, tag.as_ref(), data)?;
|
||||||
writer.position()
|
writer.position()
|
||||||
};
|
};
|
||||||
proto::write_u32(&mut slice, length as u32)
|
proto::write_u32(&mut slice, length as u32)
|
||||||
|
@ -157,7 +149,7 @@ extern fn send_async_rpc(service: u32, tag: *const u8, data: *const *const ()) {
|
||||||
send(&RpcSend {
|
send(&RpcSend {
|
||||||
async: true,
|
async: true,
|
||||||
service: service,
|
service: service,
|
||||||
tag: tag,
|
tag: tag.as_ref(),
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -206,21 +198,18 @@ extern fn watchdog_clear(id: i32) {
|
||||||
send(&WatchdogClear { id: id as usize })
|
send(&WatchdogClear { id: id as usize })
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn cache_get(key: *const u8) -> CSlice<'static, i32> {
|
extern fn cache_get(key: CSlice<u8>) -> CSlice<'static, i32> {
|
||||||
extern { fn strlen(s: *const c_char) -> size_t; }
|
send(&CacheGetRequest {
|
||||||
let key = unsafe { slice::from_raw_parts(key, strlen(key as *const c_char)) };
|
key: str::from_utf8(key.as_ref()).unwrap()
|
||||||
let key = unsafe { str::from_utf8_unchecked(key) };
|
});
|
||||||
|
|
||||||
send(&CacheGetRequest { key: key });
|
|
||||||
recv!(&CacheGetReply { value } => value.as_c_slice())
|
recv!(&CacheGetReply { value } => value.as_c_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn cache_put(key: *const u8, list: CSlice<i32>) {
|
extern fn cache_put(key: CSlice<u8>, list: CSlice<i32>) {
|
||||||
extern { fn strlen(s: *const c_char) -> size_t; }
|
send(&CachePutRequest {
|
||||||
let key = unsafe { slice::from_raw_parts(key, strlen(key as *const c_char)) };
|
key: str::from_utf8(key.as_ref()).unwrap(),
|
||||||
let key = unsafe { str::from_utf8_unchecked(key) };
|
value: list.as_ref()
|
||||||
|
});
|
||||||
send(&CachePutRequest { key: key, value: list.as_ref() });
|
|
||||||
recv!(&CachePutReply { succeeded } => {
|
recv!(&CachePutReply { succeeded } => {
|
||||||
if !succeeded {
|
if !succeeded {
|
||||||
artiq_raise!("CacheError", "cannot put into a busy cache row")
|
artiq_raise!("CacheError", "cannot put into a busy cache row")
|
||||||
|
@ -249,8 +238,8 @@ extern fn i2c_read(busno: i32, ack: bool) -> i32 {
|
||||||
unsafe fn attribute_writeback(typeinfo: *const ()) {
|
unsafe fn attribute_writeback(typeinfo: *const ()) {
|
||||||
struct Attr {
|
struct Attr {
|
||||||
offset: usize,
|
offset: usize,
|
||||||
tag: *const u8,
|
tag: CSlice<'static, u8>,
|
||||||
name: *const u8
|
name: CSlice<'static, u8>
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Type {
|
struct Type {
|
||||||
|
@ -276,7 +265,7 @@ unsafe fn attribute_writeback(typeinfo: *const ()) {
|
||||||
let attribute = *attributes;
|
let attribute = *attributes;
|
||||||
attributes = attributes.offset(1);
|
attributes = attributes.offset(1);
|
||||||
|
|
||||||
if !(*attribute).tag.is_null() {
|
if (*attribute).tag.len() > 0 {
|
||||||
send_async_rpc(0, (*attribute).tag, [
|
send_async_rpc(0, (*attribute).tag, [
|
||||||
&object as *const _ as *const (),
|
&object as *const _ as *const (),
|
||||||
&(*attribute).name as *const _ as *const (),
|
&(*attribute).name as *const _ as *const (),
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#![allow(dead_code)] // FIXME
|
|
||||||
|
|
||||||
#![feature(allocator)]
|
#![feature(allocator)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![allocator]
|
#![allocator]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![feature(lang_items, asm, alloc, collections, libc, needs_panic_runtime,
|
#![feature(lang_items, asm, alloc, collections, needs_panic_runtime,
|
||||||
unicode, raw, int_error_internals, try_from, macro_reexport,
|
unicode, raw, int_error_internals, try_from, macro_reexport,
|
||||||
allow_internal_unstable, stmt_expr_attributes)]
|
allow_internal_unstable, stmt_expr_attributes)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
@ -9,7 +9,6 @@ extern crate alloc;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
#[macro_reexport(vec, format)]
|
#[macro_reexport(vec, format)]
|
||||||
extern crate collections;
|
extern crate collections;
|
||||||
extern crate libc;
|
|
||||||
|
|
||||||
pub use core::{any, cell, clone, cmp, convert, default, hash, iter, marker, mem, num,
|
pub use core::{any, cell, clone, cmp, convert, default, hash, iter, marker, mem, num,
|
||||||
ops, option, ptr, result, sync,
|
ops, option, ptr, result, sync,
|
||||||
|
|
|
@ -17,6 +17,7 @@ compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-built
|
||||||
alloc_artiq = { path = "../liballoc_artiq" }
|
alloc_artiq = { path = "../liballoc_artiq" }
|
||||||
std_artiq = { path = "../libstd_artiq", features = ["alloc"] }
|
std_artiq = { path = "../libstd_artiq", features = ["alloc"] }
|
||||||
logger_artiq = { path = "../liblogger_artiq" }
|
logger_artiq = { path = "../liblogger_artiq" }
|
||||||
|
cslice = { version = "0.3" }
|
||||||
log = { version = "0.3", default-features = false, features = ["max_level_debug"] }
|
log = { version = "0.3", default-features = false, features = ["max_level_debug"] }
|
||||||
board = { path = "../libboard", features = ["uart_console"] }
|
board = { path = "../libboard", features = ["uart_console"] }
|
||||||
fringe = { version = "= 1.1.0", default-features = false, features = ["alloc"] }
|
fringe = { version = "= 1.1.0", default-features = false, features = ["alloc"] }
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40800000;
|
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40800000;
|
||||||
|
@ -11,14 +10,13 @@ pub const KSUPPORT_HEADER_SIZE: usize = 0x80;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Exception<'a> {
|
pub struct Exception<'a> {
|
||||||
pub name: *const u8,
|
pub name: &'a str,
|
||||||
pub file: *const u8,
|
pub file: &'a str,
|
||||||
pub line: u32,
|
pub line: u32,
|
||||||
pub column: u32,
|
pub column: u32,
|
||||||
pub function: *const u8,
|
pub function: &'a str,
|
||||||
pub message: *const u8,
|
pub message: &'a str,
|
||||||
pub param: [i64; 3],
|
pub param: [i64; 3]
|
||||||
pub phantom: PhantomData<&'a str>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -6,6 +6,7 @@ extern crate alloc_artiq;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate std_artiq as std;
|
extern crate std_artiq as std;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
extern crate cslice;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate logger_artiq;
|
extern crate logger_artiq;
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use core::slice;
|
use core::str;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
use cslice::{CSlice, CMutSlice};
|
||||||
use proto::*;
|
use proto::*;
|
||||||
use self::tag::{Tag, TagIterator, split_tag};
|
use self::tag::{Tag, TagIterator, split_tag};
|
||||||
|
|
||||||
|
@ -30,11 +31,10 @@ unsafe fn recv_value(reader: &mut Read, tag: Tag, data: &mut *mut (),
|
||||||
*ptr = read_u64(reader)?; Ok(())
|
*ptr = read_u64(reader)?; Ok(())
|
||||||
}),
|
}),
|
||||||
Tag::String => {
|
Tag::String => {
|
||||||
consume_value!(*mut u8, |ptr| {
|
consume_value!(CMutSlice<u8>, |ptr| {
|
||||||
let length = read_u32(reader)?;
|
let length = read_u32(reader)? as usize;
|
||||||
// NB: the received string includes a trailing \0
|
*ptr = CMutSlice::new(alloc(length)? as *mut u8, length);
|
||||||
*ptr = alloc(length as usize)? as *mut u8;
|
reader.read_exact((*ptr).as_mut())?;
|
||||||
reader.read_exact(slice::from_raw_parts_mut(*ptr, length as usize))?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -86,12 +86,6 @@ pub fn recv_return(reader: &mut Read, tag_bytes: &[u8], data: *mut (),
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn from_c_str<'a>(ptr: *const u8) -> &'a str {
|
|
||||||
use core::{str, slice};
|
|
||||||
extern { fn strlen(ptr: *const u8) -> usize; }
|
|
||||||
str::from_utf8_unchecked(slice::from_raw_parts(ptr as *const u8, strlen(ptr)))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::Result<()> {
|
unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::Result<()> {
|
||||||
macro_rules! consume_value {
|
macro_rules! consume_value {
|
||||||
($ty:ty, |$ptr:ident| $map:expr) => ({
|
($ty:ty, |$ptr:ident| $map:expr) => ({
|
||||||
|
@ -114,8 +108,8 @@ unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::
|
||||||
consume_value!(u64, |ptr|
|
consume_value!(u64, |ptr|
|
||||||
write_u64(writer, *ptr)),
|
write_u64(writer, *ptr)),
|
||||||
Tag::String =>
|
Tag::String =>
|
||||||
consume_value!(*const u8, |ptr|
|
consume_value!(CSlice<u8>, |ptr|
|
||||||
write_string(writer, from_c_str(*ptr))),
|
write_string(writer, str::from_utf8_unchecked((*ptr).as_ref()))),
|
||||||
Tag::Tuple(it, arity) => {
|
Tag::Tuple(it, arity) => {
|
||||||
let mut it = it.clone();
|
let mut it = it.clone();
|
||||||
write_u8(writer, arity)?;
|
write_u8(writer, arity)?;
|
||||||
|
@ -145,9 +139,9 @@ unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Tag::Keyword(it) => {
|
Tag::Keyword(it) => {
|
||||||
struct Keyword { name: *const u8, contents: () };
|
struct Keyword<'a> { name: CSlice<'a, u8>, contents: () };
|
||||||
consume_value!(Keyword, |ptr| {
|
consume_value!(Keyword, |ptr| {
|
||||||
write_string(writer, from_c_str((*ptr).name))?;
|
write_string(writer, str::from_utf8_unchecked((*ptr).name.as_ref()))?;
|
||||||
let tag = it.clone().next().expect("truncated tag");
|
let tag = it.clone().next().expect("truncated tag");
|
||||||
let mut data = &(*ptr).contents as *const ();
|
let mut data = &(*ptr).contents as *const ();
|
||||||
send_value(writer, tag, &mut data)
|
send_value(writer, tag, &mut data)
|
||||||
|
|
|
@ -62,8 +62,7 @@ struct Session<'a> {
|
||||||
congress: &'a mut Congress,
|
congress: &'a mut Congress,
|
||||||
kernel_state: KernelState,
|
kernel_state: KernelState,
|
||||||
watchdog_set: board::clock::WatchdogSet,
|
watchdog_set: board::clock::WatchdogSet,
|
||||||
log_buffer: String,
|
log_buffer: String
|
||||||
interner: BTreeSet<String>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Session<'a> {
|
impl<'a> Session<'a> {
|
||||||
|
@ -72,8 +71,7 @@ impl<'a> Session<'a> {
|
||||||
congress: congress,
|
congress: congress,
|
||||||
kernel_state: KernelState::Absent,
|
kernel_state: KernelState::Absent,
|
||||||
watchdog_set: board::clock::WatchdogSet::new(),
|
watchdog_set: board::clock::WatchdogSet::new(),
|
||||||
log_buffer: String::new(),
|
log_buffer: String::new()
|
||||||
interner: BTreeSet::new()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,6 +181,7 @@ unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> io::Resul
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
&kern::LoadReply(Err(error)) => {
|
&kern::LoadReply(Err(error)) => {
|
||||||
|
kernel::stop();
|
||||||
Err(io::Error::new(io::ErrorKind::Other,
|
Err(io::Error::new(io::ErrorKind::Other,
|
||||||
format!("cannot load kernel: {}", error)))
|
format!("cannot load kernel: {}", error)))
|
||||||
}
|
}
|
||||||
|
@ -332,22 +331,14 @@ fn process_host_message(io: &Io,
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// FIXME: gross.
|
|
||||||
fn into_c_str(interner: &mut BTreeSet<String>, s: String) -> *const u8 {
|
|
||||||
let s = s + "\0";
|
|
||||||
interner.insert(s.clone());
|
|
||||||
let p = interner.get(&s).unwrap().as_bytes().as_ptr();
|
|
||||||
p
|
|
||||||
}
|
|
||||||
let exn = kern::Exception {
|
let exn = kern::Exception {
|
||||||
name: into_c_str(&mut session.interner, name),
|
name: name.as_ref(),
|
||||||
message: into_c_str(&mut session.interner, message),
|
message: message.as_ref(),
|
||||||
param: param,
|
param: param,
|
||||||
file: into_c_str(&mut session.interner, file),
|
file: file.as_ref(),
|
||||||
line: line,
|
line: line,
|
||||||
column: column,
|
column: column,
|
||||||
function: into_c_str(&mut session.interner, function),
|
function: function.as_ref()
|
||||||
phantom: ::core::marker::PhantomData
|
|
||||||
};
|
};
|
||||||
kern_send(io, &kern::RpcRecvReply(Err(exn)))?;
|
kern_send(io, &kern::RpcRecvReply(Err(exn)))?;
|
||||||
|
|
||||||
|
@ -513,40 +504,33 @@ fn process_kern_message(io: &Io,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&kern::RunException { exception: ref exn, backtrace } => {
|
&kern::RunException {
|
||||||
|
exception: kern::Exception { name, message, param, file, line, column, function },
|
||||||
|
backtrace
|
||||||
|
} => {
|
||||||
unsafe { kernel::stop() }
|
unsafe { kernel::stop() }
|
||||||
session.kernel_state = KernelState::Absent;
|
session.kernel_state = KernelState::Absent;
|
||||||
unsafe { session.congress.cache.unborrow() }
|
unsafe { session.congress.cache.unborrow() }
|
||||||
|
|
||||||
unsafe fn from_c_str<'a>(s: *const u8) -> &'a str {
|
|
||||||
use ::libc::{c_char, size_t};
|
|
||||||
use core::slice;
|
|
||||||
extern { fn strlen(s: *const c_char) -> size_t; }
|
|
||||||
let s = slice::from_raw_parts(s, strlen(s as *const c_char));
|
|
||||||
str::from_utf8_unchecked(s)
|
|
||||||
}
|
|
||||||
let name = unsafe { from_c_str(exn.name) };
|
|
||||||
let message = unsafe { from_c_str(exn.message) };
|
|
||||||
let file = unsafe { from_c_str(exn.file) };
|
|
||||||
let function = unsafe { from_c_str(exn.function) };
|
|
||||||
match stream {
|
match stream {
|
||||||
None => {
|
None => {
|
||||||
error!("exception in flash kernel");
|
error!("exception in flash kernel");
|
||||||
error!("{}: {} {:?}", name, message, exn.param);
|
error!("{}: {} {:?}", name, message, param);
|
||||||
error!("at {}:{}:{} in {}", file, exn.line, exn.column, function);
|
error!("at {}:{}:{} in {}", file, line, column, function);
|
||||||
return Ok(true)
|
return Ok(true)
|
||||||
},
|
},
|
||||||
Some(ref mut stream) =>
|
Some(ref mut stream) => {
|
||||||
host_write(stream, host::Reply::KernelException {
|
host_write(stream, host::Reply::KernelException {
|
||||||
name: name,
|
name: name,
|
||||||
message: message,
|
message: message,
|
||||||
param: exn.param,
|
param: param,
|
||||||
file: file,
|
file: file,
|
||||||
line: exn.line,
|
line: line,
|
||||||
column: exn.column,
|
column: column,
|
||||||
function: function,
|
function: function,
|
||||||
backtrace: backtrace
|
backtrace: backtrace
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -230,18 +230,19 @@ static _Unwind_Reason_Code __artiq_uncaught_exception(
|
||||||
void *stop_parameter);
|
void *stop_parameter);
|
||||||
|
|
||||||
struct artiq_raised_exception {
|
struct artiq_raised_exception {
|
||||||
struct _Unwind_Exception unwind;
|
struct _Unwind_Exception unwind;
|
||||||
struct artiq_exception artiq;
|
struct artiq_exception artiq;
|
||||||
int handled;
|
int handled;
|
||||||
uintptr_t backtrace[1024];
|
uintptr_t backtrace[1024];
|
||||||
size_t backtrace_size;
|
size_t backtrace_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct artiq_raised_exception inflight;
|
static struct artiq_raised_exception inflight;
|
||||||
|
|
||||||
void __artiq_raise(struct artiq_exception *artiq_exn) {
|
void __artiq_raise(struct artiq_exception *artiq_exn) {
|
||||||
EH_LOG("===> raise (name=%s, msg=%s, params=[%lld,%lld,%lld])",
|
EH_LOG("===> raise (name=%.*s, msg=%.*s, params=[%lld,%lld,%lld])",
|
||||||
artiq_exn->name, artiq_exn->message,
|
(int)artiq_exn->name.len, (const char*)artiq_exn->name.ptr,
|
||||||
|
(int)artiq_exn->name.len, (const char*)artiq_exn->message.ptr,
|
||||||
(long long int)artiq_exn->param[0],
|
(long long int)artiq_exn->param[0],
|
||||||
(long long int)artiq_exn->param[1],
|
(long long int)artiq_exn->param[1],
|
||||||
(long long int)artiq_exn->param[2]);
|
(long long int)artiq_exn->param[2]);
|
||||||
|
@ -269,8 +270,6 @@ void __artiq_reraise() {
|
||||||
__artiq_raise(&inflight.artiq);
|
__artiq_raise(&inflight.artiq);
|
||||||
} else {
|
} else {
|
||||||
EH_LOG0("===> resume");
|
EH_LOG0("===> resume");
|
||||||
EH_ASSERT((inflight.artiq.typeinfo != 0) &&
|
|
||||||
"Need an exception to reraise");
|
|
||||||
_Unwind_Resume(&inflight.unwind);
|
_Unwind_Resume(&inflight.unwind);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -333,8 +332,8 @@ _Unwind_Reason_Code __artiq_personality(
|
||||||
|
|
||||||
struct artiq_raised_exception *inflight =
|
struct artiq_raised_exception *inflight =
|
||||||
(struct artiq_raised_exception*)exceptionObject;
|
(struct artiq_raised_exception*)exceptionObject;
|
||||||
EH_LOG("=> exception name=%s",
|
EH_LOG("=> exception name=%.*s",
|
||||||
inflight->artiq.name);
|
(int)inflight->artiq.name.len, (const char*)inflight->artiq.name.ptr);
|
||||||
|
|
||||||
// Get a pointer to LSDA. If there's no LSDA, this function doesn't
|
// Get a pointer to LSDA. If there's no LSDA, this function doesn't
|
||||||
// actually handle any exceptions.
|
// actually handle any exceptions.
|
||||||
|
@ -418,13 +417,17 @@ _Unwind_Reason_Code __artiq_personality(
|
||||||
if(typeInfoOffset > 0) {
|
if(typeInfoOffset > 0) {
|
||||||
unsigned encodingSize = getEncodingSize(ttypeEncoding);
|
unsigned encodingSize = getEncodingSize(ttypeEncoding);
|
||||||
const uint8_t *typeInfoPtrPtr = classInfo - typeInfoOffset * encodingSize;
|
const uint8_t *typeInfoPtrPtr = classInfo - typeInfoOffset * encodingSize;
|
||||||
uintptr_t typeInfoPtr = readEncodedPointer(&typeInfoPtrPtr, ttypeEncoding);
|
const struct slice *typeInfoPtr =
|
||||||
|
(const struct slice *)readEncodedPointer(&typeInfoPtrPtr, ttypeEncoding);
|
||||||
EH_LOG("encodingSize=%u typeInfoPtrPtr=%p typeInfoPtr=%p",
|
EH_LOG("encodingSize=%u typeInfoPtrPtr=%p typeInfoPtr=%p",
|
||||||
encodingSize, typeInfoPtrPtr, (void*)typeInfoPtr);
|
encodingSize, typeInfoPtrPtr, (void*)typeInfoPtr);
|
||||||
EH_LOG("typeInfo=%s", (char*)typeInfoPtr);
|
if(typeInfoPtr != NULL) {
|
||||||
|
EH_LOG("typeInfo=%.*s", (int)typeInfoPtr->len, (const char *)typeInfoPtr->ptr);
|
||||||
|
}
|
||||||
|
|
||||||
if(typeInfoPtr == 0 || !strcmp((char*)inflight->artiq.typeinfo,
|
if(typeInfoPtr == NULL ||
|
||||||
(char*)typeInfoPtr)) {
|
(inflight->artiq.name.len == typeInfoPtr->len &&
|
||||||
|
!memcmp(inflight->artiq.name.ptr, typeInfoPtr->ptr, typeInfoPtr->len))) {
|
||||||
EH_LOG0("matching action found");
|
EH_LOG0("matching action found");
|
||||||
exceptionMatched = 1;
|
exceptionMatched = 1;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -10,16 +10,13 @@ struct slice {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct artiq_exception {
|
struct artiq_exception {
|
||||||
union {
|
struct slice name;
|
||||||
uintptr_t typeinfo;
|
struct slice file;
|
||||||
const char *name;
|
int32_t line;
|
||||||
};
|
int32_t column;
|
||||||
const char *file;
|
struct slice function;
|
||||||
int32_t line;
|
struct slice message;
|
||||||
int32_t column;
|
int64_t param[3];
|
||||||
const char *function;
|
|
||||||
const char *message;
|
|
||||||
int64_t param[3];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -32,20 +29,6 @@ void __artiq_raise(struct artiq_exception *artiq_exn)
|
||||||
void __artiq_reraise(void)
|
void __artiq_reraise(void)
|
||||||
__attribute__((noreturn));
|
__attribute__((noreturn));
|
||||||
|
|
||||||
#define artiq_raise_from_c(exnname, exnmsg, exnparam0, exnparam1, exnparam2) \
|
|
||||||
do { \
|
|
||||||
struct artiq_exception exn = { \
|
|
||||||
.name = "0:artiq.coredevice.exceptions." exnname, \
|
|
||||||
.message = exnmsg, \
|
|
||||||
.param = { exnparam0, exnparam1, exnparam2 }, \
|
|
||||||
.file = __FILE__, \
|
|
||||||
.line = __LINE__, \
|
|
||||||
.column = -1, \
|
|
||||||
.function = __func__, \
|
|
||||||
}; \
|
|
||||||
__artiq_raise(&exn); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
/* Called by the runtime */
|
/* Called by the runtime */
|
||||||
void __artiq_terminate(struct artiq_exception *artiq_exn,
|
void __artiq_terminate(struct artiq_exception *artiq_exn,
|
||||||
struct slice backtrace)
|
struct slice backtrace)
|
||||||
|
|
|
@ -9,11 +9,14 @@
|
||||||
|
|
||||||
void __artiq_terminate(struct artiq_exception *exn,
|
void __artiq_terminate(struct artiq_exception *exn,
|
||||||
struct slice backtrace) {
|
struct slice backtrace) {
|
||||||
printf("Uncaught %s: %s (%"PRIi64", %"PRIi64", %"PRIi64")\n"
|
printf("Uncaught %.*s: %.*s (%"PRIi64", %"PRIi64", %"PRIi64")\n"
|
||||||
"at %s:%"PRIi32":%"PRIi32"\n",
|
"at %.*s:%"PRIi32":%"PRIi32"\n",
|
||||||
exn->name, exn->message,
|
(int)exn->name.len, (const char *)exn->name.ptr,
|
||||||
|
(int)exn->message.len, (const char *)exn->message.ptr,
|
||||||
exn->param[0], exn->param[1], exn->param[1],
|
exn->param[0], exn->param[1], exn->param[1],
|
||||||
exn->file, exn->line, exn->column + 1);
|
(int)exn->file.len, (const char *)exn->file.ptr,
|
||||||
|
exn->line,
|
||||||
|
exn->column + 1);
|
||||||
|
|
||||||
for(size_t i = 0; i < backtrace.len; i++) {
|
for(size_t i = 0; i < backtrace.len; i++) {
|
||||||
printf("at %"PRIxPTR"\n", ((uintptr_t*)backtrace.ptr)[i]);
|
printf("at %"PRIxPTR"\n", ((uintptr_t*)backtrace.ptr)[i]);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# RUN: %python -m artiq.compiler.testbench.jit %s
|
# RUN: %python -m artiq.compiler.testbench.jit %s
|
||||||
# RUN: %python %s
|
# RUN: %python %s
|
||||||
|
|
||||||
|
assert "xy" == "xy"
|
||||||
assert ("x" + "y") == "xy"
|
assert ("x" + "y") == "xy"
|
||||||
|
|
Loading…
Reference in New Issue