From 3bf4c06c99a913738f1125254604fb4bd3fe345f Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 21 May 2019 17:43:45 +0200 Subject: [PATCH] interp: work around limitation of constfolding in IR builder The IR builder does not appear to fold comparisons of constant inttoptr instructions to const null pointer. So do it manually during interpretatin, as a somewhat ugly hack. This fixes https://github.com/tinygo-org/tinygo/issues/363 --- interp/frame.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/interp/frame.go b/interp/frame.go index 0180ff7f..9971c0a1 100644 --- a/interp/frame.go +++ b/interp/frame.go @@ -184,6 +184,40 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re lhs := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying rhs := fr.getLocal(inst.Operand(1)).(*LocalValue).Underlying predicate := inst.IntPredicate() + if predicate == llvm.IntEQ && lhs.Type().TypeKind() == llvm.PointerTypeKind { + // Unfortunately, the const propagation in the IR builder + // doesn't handle pointer compares of inttoptr values. So we + // implement it manually here. + isNil := func(v llvm.Value) (result bool, ok bool) { + if !v.IsAConstantExpr().IsNil() && v.Opcode() == llvm.IntToPtr { + // Whether a constant inttoptr is nil is easy to + // determine. + operand := v.Operand(0) + if operand.IsConstant() { + return operand.ZExtValue() == 0, true + } + } + if !v.IsAConstantPointerNull().IsNil() { + // A constant pointer null is always null, of course. + return true, true + } + return false, false // not valid + } + lhsNil, ok1 := isNil(lhs) + rhsNil, ok2 := isNil(rhs) + if ok1 && ok2 { + if lhsNil && rhsNil { + // Both are nil, so this icmp is always evaluated to true. + fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 1, false)} + continue + } + if lhsNil != rhsNil { + // Only one of them is nil, so this comparison must return false. + fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 0, false)} + continue + } + } + } fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateICmp(predicate, lhs, rhs, "")} case !inst.IsAFCmpInst().IsNil(): lhs := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying