mirror of https://github.com/m-labs/artiq.git
Add tests for finally clause and reraising.
This commit is contained in:
parent
a83e7e2248
commit
2939d4f0f3
|
@ -979,15 +979,14 @@ class Raise(Terminator):
|
|||
|
||||
"""
|
||||
:param value: (:class:`Value`) exception value
|
||||
:param exn: (:class:`BasicBlock`) exceptional target
|
||||
:param exn: (:class:`BasicBlock` or None) exceptional target
|
||||
"""
|
||||
def __init__(self, value, exn=None, name=""):
|
||||
def __init__(self, value=None, exn=None, name=""):
|
||||
assert isinstance(value, Value)
|
||||
operands = [value]
|
||||
if exn is not None:
|
||||
assert isinstance(exn, BasicBlock)
|
||||
operands = [value, exn]
|
||||
else:
|
||||
operands = [value]
|
||||
operands.append(exn)
|
||||
super().__init__(operands, builtins.TNone(), name)
|
||||
|
||||
def opcode(self):
|
||||
|
@ -1000,6 +999,28 @@ class Raise(Terminator):
|
|||
if len(self.operands) > 1:
|
||||
return self.operands[1]
|
||||
|
||||
class Reraise(Terminator):
|
||||
"""
|
||||
A reraise instruction.
|
||||
"""
|
||||
|
||||
"""
|
||||
:param exn: (:class:`BasicBlock` or None) exceptional target
|
||||
"""
|
||||
def __init__(self, exn=None, name=""):
|
||||
operands = []
|
||||
if exn is not None:
|
||||
assert isinstance(exn, BasicBlock)
|
||||
operands.append(exn)
|
||||
super().__init__(operands, builtins.TNone(), name)
|
||||
|
||||
def opcode(self):
|
||||
return "reraise"
|
||||
|
||||
def exception_target(self):
|
||||
if len(self.operands) > 0:
|
||||
return self.operands[0]
|
||||
|
||||
class Invoke(Terminator):
|
||||
"""
|
||||
A function call operation that supports exception handling.
|
||||
|
@ -1051,12 +1072,18 @@ class LandingPad(Terminator):
|
|||
exception types corresponding to the basic block operands
|
||||
"""
|
||||
|
||||
def __init__(self, name=""):
|
||||
super().__init__([], builtins.TException(), name)
|
||||
def __init__(self, cleanup, name=""):
|
||||
super().__init__([cleanup], builtins.TException(), name)
|
||||
self.types = []
|
||||
|
||||
def opcode(self):
|
||||
return "landingpad"
|
||||
|
||||
def cleanup(self):
|
||||
return self.operands[0]
|
||||
|
||||
def clauses(self):
|
||||
return zip(self.operands, self.types)
|
||||
return zip(self.operands[1:], self.types)
|
||||
|
||||
def add_clause(self, target, typ):
|
||||
assert isinstance(target, BasicBlock)
|
||||
|
@ -1065,14 +1092,11 @@ class LandingPad(Terminator):
|
|||
self.types.append(typ.find() if typ is not None else None)
|
||||
target.uses.add(self)
|
||||
|
||||
def opcode(self):
|
||||
return "landingpad"
|
||||
|
||||
def _operands_as_string(self):
|
||||
table = []
|
||||
for typ, target in zip(self.types, self.operands):
|
||||
for target, typ in self.clauses():
|
||||
if typ is None:
|
||||
table.append("... => {}".format(target.as_operand()))
|
||||
else:
|
||||
table.append("{} => {}".format(types.TypePrinter().name(typ), target.as_operand()))
|
||||
return "[{}]".format(", ".join(table))
|
||||
return "cleanup {}, [{}]".format(self.cleanup().as_operand(), ", ".join(table))
|
||||
|
|
|
@ -466,23 +466,29 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||
self.append(ir.Branch(self.continue_target))
|
||||
|
||||
def raise_exn(self, exn):
|
||||
if exn is not None:
|
||||
loc_file = ir.Constant(self.current_loc.source_buffer.name, builtins.TStr())
|
||||
loc_line = ir.Constant(self.current_loc.line(), builtins.TInt(types.TValue(32)))
|
||||
loc_column = ir.Constant(self.current_loc.column(), builtins.TInt(types.TValue(32)))
|
||||
self.append(ir.SetAttr(exn, "__file__", loc_file))
|
||||
self.append(ir.SetAttr(exn, "__line__", loc_line))
|
||||
self.append(ir.SetAttr(exn, "__col__", loc_column))
|
||||
if self.unwind_target:
|
||||
|
||||
if self.unwind_target is not None:
|
||||
self.append(ir.Raise(exn, self.unwind_target))
|
||||
else:
|
||||
self.append(ir.Raise(exn))
|
||||
else:
|
||||
if self.unwind_target is not None:
|
||||
self.append(ir.Reraise(self.unwind_target))
|
||||
else:
|
||||
self.append(ir.Reraise())
|
||||
|
||||
def visit_Raise(self, node):
|
||||
self.raise_exn(self.visit(node.exc))
|
||||
|
||||
def visit_Try(self, node):
|
||||
dispatcher = self.add_block("try.dispatch")
|
||||
landingpad = dispatcher.append(ir.LandingPad())
|
||||
|
||||
if any(node.finalbody):
|
||||
# k for continuation
|
||||
|
@ -532,8 +538,10 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||
self.continue_target = old_continue
|
||||
self.return_target = old_return
|
||||
|
||||
cleanup = self.add_block('handler.cleanup')
|
||||
landingpad = dispatcher.append(ir.LandingPad(cleanup))
|
||||
|
||||
handlers = []
|
||||
has_catchall = False
|
||||
for handler_node in node.handlers:
|
||||
exn_type = handler_node.name_type.find()
|
||||
if handler_node.filter is not None and \
|
||||
|
@ -543,7 +551,6 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||
else:
|
||||
handler = self.add_block("handler.catchall")
|
||||
landingpad.add_clause(handler, None)
|
||||
has_catchall = True
|
||||
|
||||
self.current_block = handler
|
||||
if handler_node.name is not None:
|
||||
|
@ -561,9 +568,13 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||
self.visit(node.finalbody)
|
||||
post_finalizer = self.current_block
|
||||
|
||||
reraise = self.add_block('try.reraise')
|
||||
reraise.append(ir.Reraise(self.unwind_target))
|
||||
|
||||
self.current_block = tail = self.add_block("try.tail")
|
||||
if any(node.finalbody):
|
||||
final_targets.append(tail)
|
||||
final_targets.append(reraise)
|
||||
|
||||
if self.break_target:
|
||||
break_proxy.append(ir.Branch(finalizer))
|
||||
|
@ -575,17 +586,13 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||
body.append(ir.SetLocal(final_state, ".k", tail))
|
||||
body.append(ir.Branch(finalizer))
|
||||
|
||||
if not has_catchall:
|
||||
# Add a catch-all handler so that finally would have a chance
|
||||
# to execute.
|
||||
handler = self.add_block("handler.catchall")
|
||||
landingpad.add_clause(handler, None)
|
||||
handlers.append((handler, handler))
|
||||
cleanup.append(ir.SetLocal(final_state, ".k", reraise))
|
||||
cleanup.append(ir.Branch(finalizer))
|
||||
|
||||
for handler, post_handler in handlers:
|
||||
if not post_handler.is_terminated():
|
||||
post_handler.append(ir.SetLocal(final_state, ".k", tail))
|
||||
post_handler.append(ir.Branch(tail))
|
||||
post_handler.append(ir.Branch(finalizer))
|
||||
|
||||
if not post_finalizer.is_terminated():
|
||||
dest = post_finalizer.append(ir.GetLocal(final_state, ".k"))
|
||||
|
@ -594,6 +601,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||
if not body.is_terminated():
|
||||
body.append(ir.Branch(tail))
|
||||
|
||||
cleanup.append(ir.Reraise(self.unwind_target))
|
||||
|
||||
for handler, post_handler in handlers:
|
||||
if not post_handler.is_terminated():
|
||||
post_handler.append(ir.Branch(tail))
|
||||
|
|
|
@ -15,7 +15,9 @@ class DeadCodeEliminator:
|
|||
|
||||
def process_function(self, func):
|
||||
for block in func.basic_blocks:
|
||||
if not any(block.predecessors()) and block != func.entry():
|
||||
if not any(block.predecessors()) and \
|
||||
not any([isinstance(use, ir.SetLocal) for use in block.uses]) and \
|
||||
block != func.entry():
|
||||
self.remove_block(block)
|
||||
|
||||
def remove_block(self, block):
|
||||
|
@ -25,10 +27,6 @@ class DeadCodeEliminator:
|
|||
use.remove_incoming_block(block)
|
||||
if not any(use.operands):
|
||||
self.remove_instruction(use)
|
||||
elif isinstance(use, ir.SetLocal):
|
||||
# Setting the target for `finally` resumption, e.g.
|
||||
# setlocal(.k) %v.4, label %try.doreturn
|
||||
use.erase()
|
||||
else:
|
||||
assert False
|
||||
|
||||
|
|
|
@ -956,6 +956,7 @@ class Inferencer(algorithm.Visitor):
|
|||
def visit_Raise(self, node):
|
||||
self.generic_visit(node)
|
||||
|
||||
if node.exc is not None:
|
||||
exc_type = node.exc.type
|
||||
if not types.is_var(exc_type) and not builtins.is_exception(exc_type):
|
||||
diag = diagnostic.Diagnostic("error",
|
||||
|
|
|
@ -137,13 +137,19 @@ class LLVMIRGenerator:
|
|||
llty = ll.FunctionType(ll.DoubleType(), [ll.DoubleType(), ll.DoubleType()])
|
||||
elif name == "printf":
|
||||
llty = ll.FunctionType(ll.VoidType(), [ll.IntType(8).as_pointer()], var_arg=True)
|
||||
elif name == "__artiq_raise":
|
||||
llty = ll.FunctionType(ll.VoidType(), [self.llty_of_type(builtins.TException())])
|
||||
elif name == "__artiq_personality":
|
||||
llty = ll.FunctionType(ll.IntType(32), [], var_arg=True)
|
||||
elif name == "__artiq_raise":
|
||||
llty = ll.FunctionType(ll.VoidType(), [self.llty_of_type(builtins.TException())])
|
||||
elif name == "__artiq_reraise":
|
||||
llty = ll.FunctionType(ll.VoidType(), [])
|
||||
else:
|
||||
assert False
|
||||
return ll.Function(self.llmodule, llty, name)
|
||||
|
||||
llfun = ll.Function(self.llmodule, llty, name)
|
||||
if name in ("__artiq_raise", "__artiq_reraise", "llvm.trap"):
|
||||
llfun.attributes.add("noreturn")
|
||||
return llfun
|
||||
|
||||
def map(self, value):
|
||||
if isinstance(value, (ir.Argument, ir.Instruction, ir.BasicBlock)):
|
||||
|
@ -599,12 +605,20 @@ class LLVMIRGenerator:
|
|||
llinsn.attributes.add('noreturn')
|
||||
return llinsn
|
||||
|
||||
def process_Reraise(self, insn):
|
||||
llinsn = self.llbuilder.call(self.llbuiltin("__artiq_reraise"), [],
|
||||
name=insn.name)
|
||||
llinsn.attributes.add('noreturn')
|
||||
self.llbuilder.unreachable()
|
||||
return llinsn
|
||||
|
||||
def process_LandingPad(self, insn):
|
||||
# Layout on return from landing pad: {%_Unwind_Exception*, %Exception*}
|
||||
lllandingpadty = ll.LiteralStructType([ll.IntType(8).as_pointer(),
|
||||
ll.IntType(8).as_pointer()])
|
||||
lllandingpad = self.llbuilder.landingpad(lllandingpadty,
|
||||
self.llbuiltin("__artiq_personality"))
|
||||
self.llbuiltin("__artiq_personality"),
|
||||
cleanup=True)
|
||||
llrawexn = self.llbuilder.extract_value(lllandingpad, 1)
|
||||
llexn = self.llbuilder.bitcast(llrawexn, self.llty_of_type(insn.type))
|
||||
llexnnameptr = self.llbuilder.gep(llexn, [self.llindex(0), self.llindex(0)])
|
||||
|
@ -627,7 +641,7 @@ class LLVMIRGenerator:
|
|||
self.llbuilder.branch(self.map(target))
|
||||
|
||||
if self.llbuilder.basic_block.terminator is None:
|
||||
self.llbuilder.resume(lllandingpad)
|
||||
self.llbuilder.branch(self.map(insn.cleanup()))
|
||||
|
||||
return llexn
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# RUN: %python -m artiq.compiler.testbench.jit %s
|
||||
# RUN: %python -m artiq.compiler.testbench.jit %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
# REQUIRES: exceptions
|
||||
|
||||
try:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# RUN: %python -m artiq.compiler.testbench.jit %s
|
||||
# RUN: %python -m artiq.compiler.testbench.jit %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
# REQUIRES: exceptions
|
||||
|
||||
def catch(f):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# RUN: %python -m artiq.compiler.testbench.jit %s
|
||||
# RUN: %python -m artiq.compiler.testbench.jit %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
# REQUIRES: exceptions
|
||||
|
||||
def catch(f):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# RUN: %python -m artiq.compiler.testbench.jit %s
|
||||
# RUN: %python -m artiq.compiler.testbench.jit %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
# REQUIRES: exceptions
|
||||
|
||||
def f():
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# RUN: %python -m artiq.compiler.testbench.jit %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
# REQUIRES: exceptions
|
||||
|
||||
def f():
|
||||
try:
|
||||
1/0
|
||||
finally:
|
||||
print("f-fin")
|
||||
print("f-out")
|
||||
|
||||
def g():
|
||||
try:
|
||||
f()
|
||||
except:
|
||||
print("g-except")
|
||||
|
||||
# CHECK-L: f-fin
|
||||
# CHECK-NOT-L: f-out
|
||||
# CHECK-L: g-except
|
||||
g()
|
|
@ -0,0 +1,17 @@
|
|||
# RUN: %python -m artiq.compiler.testbench.jit %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
# REQUIRES: exceptions
|
||||
|
||||
def f():
|
||||
try:
|
||||
1/0
|
||||
except:
|
||||
print("f-except")
|
||||
finally:
|
||||
print("f-fin")
|
||||
print("f-out")
|
||||
|
||||
# CHECK-L: f-except
|
||||
# CHECK-L: f-fin
|
||||
# CHECK-L: f-out
|
||||
f()
|
|
@ -0,0 +1,23 @@
|
|||
# RUN: %python -m artiq.compiler.testbench.jit %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
# REQUIRES: exceptions
|
||||
|
||||
def f():
|
||||
try:
|
||||
1/0
|
||||
finally:
|
||||
print("f-fin")
|
||||
raise ValueError()
|
||||
|
||||
def g():
|
||||
try:
|
||||
f()
|
||||
except ZeroDivisionError:
|
||||
print("g-except-zde")
|
||||
except ValueError:
|
||||
print("g-except-ve")
|
||||
|
||||
# CHECK-L: f-fin
|
||||
# CHECK-L: g-except-ve
|
||||
# CHECK-NOT-L: g-except-zde
|
||||
g()
|
|
@ -0,0 +1,21 @@
|
|||
# RUN: %python -m artiq.compiler.testbench.jit %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
# REQUIRES: exceptions
|
||||
|
||||
def f():
|
||||
try:
|
||||
1/0
|
||||
finally:
|
||||
print("f-fin")
|
||||
return
|
||||
|
||||
def g():
|
||||
try:
|
||||
f()
|
||||
except:
|
||||
print("g-except")
|
||||
|
||||
# CHECK-L: f-fin
|
||||
# CHECK-NOT-L: f-out
|
||||
# CHECK-NOT-L: g-except
|
||||
g()
|
|
@ -0,0 +1,16 @@
|
|||
# RUN: %not %python -m artiq.compiler.testbench.jit %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
# REQUIRES: exceptions
|
||||
|
||||
def f():
|
||||
# CHECK-L: Uncaught ZeroDivisionError
|
||||
# CHECK-L: at input.py:${LINE:+1}:
|
||||
1/0
|
||||
|
||||
def g():
|
||||
try:
|
||||
f()
|
||||
except:
|
||||
raise
|
||||
|
||||
g()
|
|
@ -0,0 +1,16 @@
|
|||
# RUN: %not %python -m artiq.compiler.testbench.jit %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
# REQUIRES: exceptions
|
||||
|
||||
def f():
|
||||
1/0
|
||||
|
||||
def g():
|
||||
try:
|
||||
f()
|
||||
except Exception as e:
|
||||
# CHECK-L: Uncaught ZeroDivisionError
|
||||
# CHECK-L: at input.py:${LINE:+1}:
|
||||
raise e
|
||||
|
||||
g()
|
|
@ -1,6 +1,7 @@
|
|||
# RUN: %not %python -m artiq.compiler.testbench.jit %s
|
||||
# RUN: %not %python -m artiq.compiler.testbench.jit %s >%t
|
||||
# RUN: OutputCheck %s --file-to-check=%t
|
||||
# REQUIRES: exceptions
|
||||
|
||||
# CHECK-L: Uncaught ZeroDivisionError: cannot divide by zero (0, 0, 0)
|
||||
# CHECK-L: at input.py:${LINE:+1}:0
|
||||
# CHECK-L: at input.py:${LINE:+1}:
|
||||
1/0
|
||||
|
|
|
@ -62,3 +62,15 @@ def i():
|
|||
# CHECK-NOT-L: i-out
|
||||
# CHECK-L: i 30
|
||||
print("i", i())
|
||||
|
||||
def j():
|
||||
try:
|
||||
print("j-try")
|
||||
finally:
|
||||
print("j-finally")
|
||||
print("j-out")
|
||||
|
||||
# CHECK-L: j-try
|
||||
# CHECK-L: j-finally
|
||||
# CHECK-L: j-out
|
||||
print("j", j())
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
/* Logging */
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define EH_LOG0(fmt) fprintf(stderr, "__artiq_personality: " fmt "\n")
|
||||
#define EH_LOG(fmt, ...) fprintf(stderr, "__artiq_personality: " fmt "\n", __VA_ARGS__)
|
||||
#define EH_LOG0(fmt) fprintf(stderr, "%s: " fmt "\n", __func__)
|
||||
#define EH_LOG(fmt, ...) fprintf(stderr, "%s: " fmt "\n", __func__, __VA_ARGS__)
|
||||
#else
|
||||
#define EH_LOG0(fmt)
|
||||
#define EH_LOG(fmt, ...)
|
||||
|
@ -17,7 +17,7 @@
|
|||
|
||||
#define EH_FAIL(err) \
|
||||
do { \
|
||||
fprintf(stderr, "__artiq_personality fatal: %s\n", err); \
|
||||
fprintf(stderr, "%s fatal: %s\n", __func__, err); \
|
||||
abort(); \
|
||||
} while(0)
|
||||
|
||||
|
@ -195,37 +195,61 @@ static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) {
|
|||
}
|
||||
|
||||
|
||||
/* Raising and catching */
|
||||
/* Raising */
|
||||
|
||||
#define ARTIQ_EXCEPTION_CLASS 0x4152545141525451LL // 'ARTQARTQ'
|
||||
|
||||
static void __artiq_cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *exc);
|
||||
|
||||
struct artiq_raised_exception {
|
||||
struct _Unwind_Exception unwind;
|
||||
struct artiq_exception artiq;
|
||||
int handled;
|
||||
};
|
||||
|
||||
static struct artiq_raised_exception inflight;
|
||||
|
||||
void __artiq_raise(struct artiq_exception *artiq_exn) {
|
||||
EH_LOG("===> raise (name=%s)", artiq_exn->name);
|
||||
|
||||
memmove(&inflight.artiq, artiq_exn, sizeof(struct artiq_exception));
|
||||
inflight.unwind.exception_class = ARTIQ_EXCEPTION_CLASS;
|
||||
inflight.unwind.exception_cleanup = &__artiq_cleanup;
|
||||
inflight.handled = 0;
|
||||
|
||||
_Unwind_Reason_Code result = _Unwind_RaiseException(&inflight.unwind);
|
||||
EH_ASSERT((result == _URC_END_OF_STACK) &&
|
||||
"Unexpected error during unwinding");
|
||||
|
||||
// If we're here, there are no handlers, only cleanups.
|
||||
__artiq_terminate(&inflight.artiq);
|
||||
}
|
||||
|
||||
void __artiq_reraise() {
|
||||
if(inflight.handled) {
|
||||
EH_LOG0("===> reraise");
|
||||
__artiq_raise(&inflight.artiq);
|
||||
} else {
|
||||
EH_LOG0("===> resume");
|
||||
EH_ASSERT((inflight.artiq.typeinfo != 0) &&
|
||||
"Need an exception to reraise");
|
||||
_Unwind_Resume(&inflight.unwind);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Catching */
|
||||
|
||||
// The code below does not refer to the `inflight` global.
|
||||
|
||||
static void __artiq_cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *exc) {
|
||||
EH_LOG0("===> cleanup");
|
||||
struct artiq_raised_exception *inflight = (struct artiq_raised_exception*) exc;
|
||||
// The in-flight exception is statically allocated, so we don't need to free it.
|
||||
// But, we clear it to mark it as processed.
|
||||
memset(&inflight->artiq, 0, sizeof(struct artiq_exception));
|
||||
}
|
||||
|
||||
void __artiq_raise(struct artiq_exception *artiq_exn) {
|
||||
static struct artiq_raised_exception inflight;
|
||||
memcpy(&inflight.artiq, artiq_exn, sizeof(struct artiq_exception));
|
||||
inflight.unwind.exception_class = ARTIQ_EXCEPTION_CLASS;
|
||||
inflight.unwind.exception_cleanup = &__artiq_cleanup;
|
||||
|
||||
_Unwind_Reason_Code result = _Unwind_RaiseException(&inflight.unwind);
|
||||
if(result == _URC_END_OF_STACK) {
|
||||
__artiq_terminate(&inflight.artiq);
|
||||
} else {
|
||||
fprintf(stderr, "__artiq_raise: unexpected error (%d)\n", result);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
_Unwind_Reason_Code __artiq_personality(
|
||||
int version, _Unwind_Action actions, uint64_t exceptionClass,
|
||||
struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) {
|
||||
|
@ -345,6 +369,9 @@ _Unwind_Reason_Code __artiq_personality(
|
|||
if(!(actions & _UA_SEARCH_PHASE)) {
|
||||
EH_LOG0("=> jumping to landing pad");
|
||||
|
||||
if(actions & _UA_HANDLER_FRAME)
|
||||
inflight->handled = 1;
|
||||
|
||||
_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
|
||||
(uintptr_t)exceptionObject);
|
||||
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
|
||||
|
|
|
@ -19,10 +19,15 @@ struct artiq_exception {
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void __artiq_terminate(struct artiq_exception *artiq_exn)
|
||||
/* Provided by the runtime */
|
||||
void __artiq_raise(struct artiq_exception *artiq_exn)
|
||||
__attribute__((noreturn));
|
||||
void __artiq_reraise()
|
||||
__attribute__((noreturn));
|
||||
|
||||
void __artiq_raise(struct artiq_exception *artiq_exn);
|
||||
/* Called by the runtime */
|
||||
void __artiq_terminate(struct artiq_exception *artiq_exn)
|
||||
__attribute__((noreturn));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue