Skip to content

Commit 0db26b0

Browse files
aykevldeadprogram
authored andcommitted
interp: support integer icmp of ptrtoint
This kind of code might be generated by the switch implementation of func values. The func value is represented as a ptrtoint, and before calling it, it is compared against 0.
1 parent 4f7a650 commit 0db26b0

File tree

4 files changed

+57
-13
lines changed

4 files changed

+57
-13
lines changed

interp/frame.go

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -194,20 +194,28 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
194194
lhs := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
195195
rhs := fr.getLocal(inst.Operand(1)).(*LocalValue).Underlying
196196
predicate := inst.IntPredicate()
197-
if predicate == llvm.IntEQ && lhs.Type().TypeKind() == llvm.PointerTypeKind {
198-
// Unfortunately, the const propagation in the IR builder
199-
// doesn't handle pointer compares of inttoptr values. So we
200-
// implement it manually here.
201-
lhsNil, ok1 := isPointerNil(lhs)
202-
rhsNil, ok2 := isPointerNil(rhs)
197+
if predicate == llvm.IntEQ {
198+
var lhsZero, rhsZero bool
199+
var ok1, ok2 bool
200+
if lhs.Type().TypeKind() == llvm.PointerTypeKind {
201+
// Unfortunately, the const propagation in the IR builder
202+
// doesn't handle pointer compares of inttoptr values. So we
203+
// implement it manually here.
204+
lhsZero, ok1 = isPointerNil(lhs)
205+
rhsZero, ok2 = isPointerNil(rhs)
206+
}
207+
if lhs.Type().TypeKind() == llvm.IntegerTypeKind {
208+
lhsZero, ok1 = isZero(lhs)
209+
rhsZero, ok2 = isZero(rhs)
210+
}
203211
if ok1 && ok2 {
204-
if lhsNil && rhsNil {
205-
// Both are nil, so this icmp is always evaluated to true.
212+
if lhsZero && rhsZero {
213+
// Both are zero, so this icmp is always evaluated to true.
206214
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 1, false)}
207215
continue
208216
}
209-
if lhsNil != rhsNil {
210-
// Only one of them is nil, so this comparison must return false.
217+
if lhsZero != rhsZero {
218+
// Only one of them is zero, so this comparison must return false.
211219
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 0, false)}
212220
continue
213221
}

interp/testdata/consteval.ll

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
22
target triple = "x86_64--linux"
33

44
@intToPtrResult = global i8 0
5+
@ptrToIntResult = global i8 0
56

67
define void @runtime.initAll() {
78
call void @main.init()
@@ -10,6 +11,7 @@ define void @runtime.initAll() {
1011

1112
define internal void @main.init() {
1213
call void @testIntToPtr()
14+
call void @testPtrToInt()
1315
ret void
1416
}
1517

@@ -25,3 +27,16 @@ b:
2527
store i8 2, i8* @intToPtrResult
2628
ret void
2729
}
30+
31+
define internal void @testPtrToInt() {
32+
%zero = icmp eq i64 ptrtoint (i8* @ptrToIntResult to i64), 0
33+
br i1 %zero, label %a, label %b
34+
a:
35+
; should not be reached
36+
store i8 1, i8* @ptrToIntResult
37+
ret void
38+
b:
39+
; should be reached
40+
store i8 2, i8* @ptrToIntResult
41+
ret void
42+
}

interp/testdata/consteval.out.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
22
target triple = "x86_64--linux"
33

44
@intToPtrResult = local_unnamed_addr global i8 2
5+
@ptrToIntResult = local_unnamed_addr global i8 2
56

67
define void @runtime.initAll() local_unnamed_addr {
78
ret void

interp/utils.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ func isPointerNil(v llvm.Value) (result bool, ok bool) {
6060
case llvm.IntToPtr:
6161
// Whether a constant inttoptr is nil is easy to
6262
// determine.
63-
operand := v.Operand(0)
64-
if operand.IsConstant() {
65-
return operand.ZExtValue() == 0, true
63+
result, ok = isZero(v.Operand(0))
64+
if ok {
65+
return
6666
}
6767
case llvm.BitCast, llvm.GetElementPtr:
6868
// These const instructions are just a kind of wrappers for the
@@ -74,6 +74,26 @@ func isPointerNil(v llvm.Value) (result bool, ok bool) {
7474
// A constant pointer null is always null, of course.
7575
return true, true
7676
}
77+
if !v.IsAGlobalValue().IsNil() {
78+
// A global value is never null.
79+
return false, true
80+
}
81+
return false, false // not valid
82+
}
83+
84+
// isZero returns whether the value in v is the integer zero, and whether that
85+
// can be known right now.
86+
func isZero(v llvm.Value) (result bool, ok bool) {
87+
if !v.IsAConstantExpr().IsNil() {
88+
switch v.Opcode() {
89+
case llvm.PtrToInt:
90+
return isPointerNil(v.Operand(0))
91+
}
92+
}
93+
if !v.IsAConstantInt().IsNil() {
94+
val := v.ZExtValue()
95+
return val == 0, true
96+
}
7797
return false, false // not valid
7898
}
7999

0 commit comments

Comments
 (0)