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.
Этот коммит содержится в:
родитель
4f7a650614
коммит
0db26b0662
4 изменённых файлов: 57 добавлений и 13 удалений
|
@ -194,20 +194,28 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||||
lhs := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
|
lhs := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
|
||||||
rhs := fr.getLocal(inst.Operand(1)).(*LocalValue).Underlying
|
rhs := fr.getLocal(inst.Operand(1)).(*LocalValue).Underlying
|
||||||
predicate := inst.IntPredicate()
|
predicate := inst.IntPredicate()
|
||||||
if predicate == llvm.IntEQ && lhs.Type().TypeKind() == llvm.PointerTypeKind {
|
if predicate == llvm.IntEQ {
|
||||||
|
var lhsZero, rhsZero bool
|
||||||
|
var ok1, ok2 bool
|
||||||
|
if lhs.Type().TypeKind() == llvm.PointerTypeKind {
|
||||||
// Unfortunately, the const propagation in the IR builder
|
// Unfortunately, the const propagation in the IR builder
|
||||||
// doesn't handle pointer compares of inttoptr values. So we
|
// doesn't handle pointer compares of inttoptr values. So we
|
||||||
// implement it manually here.
|
// implement it manually here.
|
||||||
lhsNil, ok1 := isPointerNil(lhs)
|
lhsZero, ok1 = isPointerNil(lhs)
|
||||||
rhsNil, ok2 := isPointerNil(rhs)
|
rhsZero, ok2 = isPointerNil(rhs)
|
||||||
|
}
|
||||||
|
if lhs.Type().TypeKind() == llvm.IntegerTypeKind {
|
||||||
|
lhsZero, ok1 = isZero(lhs)
|
||||||
|
rhsZero, ok2 = isZero(rhs)
|
||||||
|
}
|
||||||
if ok1 && ok2 {
|
if ok1 && ok2 {
|
||||||
if lhsNil && rhsNil {
|
if lhsZero && rhsZero {
|
||||||
// Both are nil, so this icmp is always evaluated to true.
|
// Both are zero, so this icmp is always evaluated to true.
|
||||||
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 1, false)}
|
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 1, false)}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if lhsNil != rhsNil {
|
if lhsZero != rhsZero {
|
||||||
// Only one of them is nil, so this comparison must return false.
|
// Only one of them is zero, so this comparison must return false.
|
||||||
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 0, false)}
|
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 0, false)}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
15
interp/testdata/consteval.ll
предоставленный
15
interp/testdata/consteval.ll
предоставленный
|
@ -2,6 +2,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||||
target triple = "x86_64--linux"
|
target triple = "x86_64--linux"
|
||||||
|
|
||||||
@intToPtrResult = global i8 0
|
@intToPtrResult = global i8 0
|
||||||
|
@ptrToIntResult = global i8 0
|
||||||
|
|
||||||
define void @runtime.initAll() {
|
define void @runtime.initAll() {
|
||||||
call void @main.init()
|
call void @main.init()
|
||||||
|
@ -10,6 +11,7 @@ define void @runtime.initAll() {
|
||||||
|
|
||||||
define internal void @main.init() {
|
define internal void @main.init() {
|
||||||
call void @testIntToPtr()
|
call void @testIntToPtr()
|
||||||
|
call void @testPtrToInt()
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,3 +27,16 @@ b:
|
||||||
store i8 2, i8* @intToPtrResult
|
store i8 2, i8* @intToPtrResult
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define internal void @testPtrToInt() {
|
||||||
|
%zero = icmp eq i64 ptrtoint (i8* @ptrToIntResult to i64), 0
|
||||||
|
br i1 %zero, label %a, label %b
|
||||||
|
a:
|
||||||
|
; should not be reached
|
||||||
|
store i8 1, i8* @ptrToIntResult
|
||||||
|
ret void
|
||||||
|
b:
|
||||||
|
; should be reached
|
||||||
|
store i8 2, i8* @ptrToIntResult
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
1
interp/testdata/consteval.out.ll
предоставленный
1
interp/testdata/consteval.out.ll
предоставленный
|
@ -2,6 +2,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||||
target triple = "x86_64--linux"
|
target triple = "x86_64--linux"
|
||||||
|
|
||||||
@intToPtrResult = local_unnamed_addr global i8 2
|
@intToPtrResult = local_unnamed_addr global i8 2
|
||||||
|
@ptrToIntResult = local_unnamed_addr global i8 2
|
||||||
|
|
||||||
define void @runtime.initAll() local_unnamed_addr {
|
define void @runtime.initAll() local_unnamed_addr {
|
||||||
ret void
|
ret void
|
||||||
|
|
|
@ -60,9 +60,9 @@ func isPointerNil(v llvm.Value) (result bool, ok bool) {
|
||||||
case llvm.IntToPtr:
|
case llvm.IntToPtr:
|
||||||
// Whether a constant inttoptr is nil is easy to
|
// Whether a constant inttoptr is nil is easy to
|
||||||
// determine.
|
// determine.
|
||||||
operand := v.Operand(0)
|
result, ok = isZero(v.Operand(0))
|
||||||
if operand.IsConstant() {
|
if ok {
|
||||||
return operand.ZExtValue() == 0, true
|
return
|
||||||
}
|
}
|
||||||
case llvm.BitCast, llvm.GetElementPtr:
|
case llvm.BitCast, llvm.GetElementPtr:
|
||||||
// These const instructions are just a kind of wrappers for the
|
// These const instructions are just a kind of wrappers for the
|
||||||
|
@ -74,6 +74,26 @@ func isPointerNil(v llvm.Value) (result bool, ok bool) {
|
||||||
// A constant pointer null is always null, of course.
|
// A constant pointer null is always null, of course.
|
||||||
return true, true
|
return true, true
|
||||||
}
|
}
|
||||||
|
if !v.IsAGlobalValue().IsNil() {
|
||||||
|
// A global value is never null.
|
||||||
|
return false, true
|
||||||
|
}
|
||||||
|
return false, false // not valid
|
||||||
|
}
|
||||||
|
|
||||||
|
// isZero returns whether the value in v is the integer zero, and whether that
|
||||||
|
// can be known right now.
|
||||||
|
func isZero(v llvm.Value) (result bool, ok bool) {
|
||||||
|
if !v.IsAConstantExpr().IsNil() {
|
||||||
|
switch v.Opcode() {
|
||||||
|
case llvm.PtrToInt:
|
||||||
|
return isPointerNil(v.Operand(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !v.IsAConstantInt().IsNil() {
|
||||||
|
val := v.ZExtValue()
|
||||||
|
return val == 0, true
|
||||||
|
}
|
||||||
return false, false // not valid
|
return false, false // not valid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче