diff --git a/pkgs/boots/graph.dora b/pkgs/boots/graph.dora index e29342b39..c2213a072 100644 --- a/pkgs/boots/graph.dora +++ b/pkgs/boots/graph.dora @@ -556,6 +556,18 @@ impl Block { inst } + pub fn prependInst(inst: Inst): Inst { + assert(inst.block.isNone() && !inst.hasId()); + + inst.block = Some(self); + self.graph.getOrPanic().assignNextInstId(inst); + + self.instructions.prependInst(inst); + inst.registerUses(); + + inst + } + pub fn splitAfter(inst: Inst): Block { assert(inst.getBlock() === self); assert(!inst.isTerminator()); @@ -3167,6 +3179,16 @@ impl InstLinkedList { self.last.getOrPanic() } + fn prependInst(inst: Inst) { + let first = self.first.getOrPanic(); + first.previous = Some(inst); + + inst.previous = None[Inst]; + inst.next = Some[Inst](first); + + self.first = Some(inst); + } + fn appendInst(inst: Inst) { if self.first.isNone() { inst.previous = None; diff --git a/pkgs/boots/graph_builder.dora b/pkgs/boots/graph_builder.dora index cdf2b6c7c..d948400bb 100644 --- a/pkgs/boots/graph_builder.dora +++ b/pkgs/boots/graph_builder.dora @@ -1206,9 +1206,7 @@ impl SsaGen { let value = self.readVariable(opnd, self.current()); let ty = self.graphTy(ty); - if self.returnValue.isSome() { - let returnValue = self.returnValue.getOrPanic(); - + if self.returnValue is Some(returnValue) { let phi = if returnValue.getBlock() == exitBlock { assert(returnValue.isPhi()); returnValue @@ -1219,8 +1217,8 @@ impl SsaGen { phi }; - // Here we add input to phi after the phi was already appended to - // the graph. Therefore we need to register the input manually. + // Here we add another input to the phi after the phi was already appended + // to the graph. Therefore we need to register the input manually. let input = phi.addInput(value); value.addUse(input); self.returnValue = Some(phi); diff --git a/pkgs/boots/inlining.dora b/pkgs/boots/inlining.dora index af67e8044..3728d1d2b 100644 --- a/pkgs/boots/inlining.dora +++ b/pkgs/boots/inlining.dora @@ -1,6 +1,6 @@ use package::bytecode::{BytecodeType, FunctionId}; use package::compilation::CompilationInfo; -use package::graph::{Graph, Inst, Op}; +use package::graph::{createUndefInst, Graph, Inst, Op}; use package::graph_builder; use package::interface as iface; @@ -43,11 +43,18 @@ fn inline(ci: CompilationInfo, graph: Graph, inst: Inst, fctId: FunctionId, type if returnValue.isSome() { let returnValue = returnValue.getOrPanic(); inst.replaceAllUsesWith(returnValue); - } - if inst.hasUses() { - println("ouch: ${ci.getDisplayName()}"); - // println(dumpGraph(Some[CompilationInfo](ci), graph, config.architecture)); - // println("ouch"); + } else if inst.hasUses() { + // This call has users but the inlined function has no return value + // because it e.g. crashes unconditionally. In this case newBlock is + // unreachable and will be removed by cfg_simplification. + // There is no value to replace all uses of the call return value, so + // replace it with Undef. Undef also needs to be in newBlock to not + // break SSA. + let undef = createUndefInst(); + newBlock.prependInst(undef); + inst.replaceAllUsesWith(undef); + } else { + assert(inst.getValueType().isUnit()); } inst.remove(); } diff --git a/tests/boots/opt/inline-unreachable.dora b/tests/boots/opt/inline-unreachable.dora new file mode 100644 index 000000000..ab4776115 --- /dev/null +++ b/tests/boots/opt/inline-unreachable.dora @@ -0,0 +1,18 @@ +//= boots +//= error code 1 + +fn main() { + testme(); +} + +@Optimize +fn testme(): Int { + let x = myFatalError[Int](); + // Everything here is unreachable after inlining. + println("x = ${x}"); + x + 1 +} + +fn myFatalError[T](): T { + std::fatalError[T]("not yet implemented") +}