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:
whitequark 2017-02-03 11:46:45 +00:00
parent e13d8919ff
commit fd8b11532f
17 changed files with 188 additions and 252 deletions

View File

@ -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.

View File

@ -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,9 +1556,9 @@ 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
@ -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

View File

@ -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,10 +816,6 @@ 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):
llelt = self.llbuilder.gep(lllst, [llidx], inbounds=True)
llvalue = self.llbuilder.load(llelt)
else:
llelts = self.llbuilder.extract_value(lllst, 0) llelts = self.llbuilder.extract_value(lllst, 0)
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True) llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
llvalue = self.llbuilder.load(llelt) llvalue = self.llbuilder.load(llelt)
@ -843,9 +826,6 @@ 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):
llelt = self.llbuilder.gep(lllst, [llidx], inbounds=True)
else:
llelts = self.llbuilder.extract_value(lllst, 0) llelts = self.llbuilder.extract_value(lllst, 0)
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True) 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)
@ -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.call(self.llbuiltin("strlen"), [self.map(collection)])
else:
return self.llbuilder.extract_value(self.map(collection), 1) 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,22 +1540,37 @@ 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)
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)) self.llbuilder.branch(self.map(target))
if self.llbuilder.basic_block.terminator is None: if self.llbuilder.basic_block.terminator is None:

View File

@ -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",

View File

@ -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),

View File

@ -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 (),

View File

@ -1,5 +1,3 @@
#![allow(dead_code)] // FIXME
#![feature(allocator)] #![feature(allocator)]
#![no_std] #![no_std]
#![allocator] #![allocator]

View File

@ -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,

View File

@ -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"] }

View File

@ -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)]

View File

@ -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;

View File

@ -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)

View File

@ -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,42 +504,35 @@ 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
}) })
} }
} }
}
request => unexpected!("unexpected request {:?} from kernel CPU", request) request => unexpected!("unexpected request {:?} from kernel CPU", request)
}.and(Ok(false)) }.and(Ok(false))

View File

@ -240,8 +240,9 @@ struct artiq_raised_exception {
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;

View File

@ -10,15 +10,12 @@ struct slice {
}; };
struct artiq_exception { struct artiq_exception {
union { struct slice name;
uintptr_t typeinfo; struct slice file;
const char *name;
};
const char *file;
int32_t line; int32_t line;
int32_t column; int32_t column;
const char *function; struct slice function;
const char *message; struct slice message;
int64_t param[3]; int64_t param[3];
}; };
@ -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)

View File

@ -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]);

View File

@ -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"