Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 20 additions & 57 deletions interp/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,16 +346,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
dstObj.buffer = dstBuf
mem.put(dst.index(), dstObj)
}
switch inst.llvmInst.Type().IntTypeWidth() {
case 16:
locals[inst.localIndex] = literalValue{uint16(n)}
case 32:
locals[inst.localIndex] = literalValue{uint32(n)}
case 64:
locals[inst.localIndex] = literalValue{uint64(n)}
default:
panic("unknown integer type width")
}
locals[inst.localIndex] = makeLiteralInt(n, inst.llvmInst.Type().IntTypeWidth())
case strings.HasPrefix(callFn.name, "llvm.memcpy.p0") || strings.HasPrefix(callFn.name, "llvm.memmove.p0"):
// Copy a block of memory from one pointer to another.
dst, err := operands[1].asPointer(r)
Expand Down Expand Up @@ -647,16 +638,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
}
// GEP on fixed pointer value (for example, memory-mapped I/O).
ptrValue := operands[0].Uint() + offset
switch operands[0].len(r) {
case 8:
locals[inst.localIndex] = literalValue{uint64(ptrValue)}
case 4:
locals[inst.localIndex] = literalValue{uint32(ptrValue)}
case 2:
locals[inst.localIndex] = literalValue{uint16(ptrValue)}
default:
panic("pointer operand is not of a known pointer size")
}
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
continue
}
ptr = ptr.addOffset(int64(offset))
Expand Down Expand Up @@ -754,30 +736,33 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if err == nil {
// The lhs is a pointer. This sometimes happens for particular
// pointer tricks.
switch inst.opcode {
case llvm.Add:
if inst.opcode == llvm.Add {
// This likely means this is part of a
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
lhsPtr = lhsPtr.addOffset(int64(rhs.Uint()))
locals[inst.localIndex] = lhsPtr
continue
case llvm.Xor:
if rhs.Uint() == 0 {
// Special workaround for strings.noescape, see
// src/strings/builder.go in the Go source tree. This is
// the identity operator, so we can return the input.
locals[inst.localIndex] = lhs
continue
}
default:
} else if inst.opcode == llvm.Xor && rhs.Uint() == 0 {
// Special workaround for strings.noescape, see
// src/strings/builder.go in the Go source tree. This is
// the identity operator, so we can return the input.
locals[inst.localIndex] = lhs
} else if inst.opcode == llvm.And && rhs.Uint() < 8 {
// This is probably part of a pattern to get the lower bits
// of a pointer for pointer tagging, like this:
// uintptr(unsafe.Pointer(t)) & 0b11
// We can actually support this easily by ANDing with the
// pointer offset.
result := uint64(lhsPtr.offset()) & rhs.Uint()
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
} else {
// Catch-all for weird operations that should just be done
// at runtime.
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
if err != nil {
return nil, mem, err
}
continue
}
continue
}
var result uint64
switch inst.opcode {
Expand Down Expand Up @@ -810,18 +795,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
default:
panic("unreachable")
}
switch lhs.len(r) {
case 8:
locals[inst.localIndex] = literalValue{result}
case 4:
locals[inst.localIndex] = literalValue{uint32(result)}
case 2:
locals[inst.localIndex] = literalValue{uint16(result)}
case 1:
locals[inst.localIndex] = literalValue{uint8(result)}
default:
panic("unknown integer size")
}
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
if r.debug {
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", lhs, rhs, "->", result)
}
Expand All @@ -843,18 +817,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
if r.debug {
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth)
}
switch bitwidth {
case 64:
locals[inst.localIndex] = literalValue{value}
case 32:
locals[inst.localIndex] = literalValue{uint32(value)}
case 16:
locals[inst.localIndex] = literalValue{uint16(value)}
case 8:
locals[inst.localIndex] = literalValue{uint8(value)}
default:
panic("unknown integer size in sext/zext/trunc")
}
locals[inst.localIndex] = makeLiteralInt(value, int(bitwidth))
case llvm.SIToFP, llvm.UIToFP:
var value float64
switch inst.opcode {
Expand Down
16 changes: 16 additions & 0 deletions interp/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,22 @@ type literalValue struct {
value interface{}
}

// Make a literalValue given the number of bits.
func makeLiteralInt(value uint64, bits int) literalValue {
switch bits {
case 64:
return literalValue{value}
case 32:
return literalValue{uint32(value)}
case 16:
return literalValue{uint16(value)}
case 8:
return literalValue{uint8(value)}
default:
panic("unknown integer size")
}
}

func (v literalValue) len(r *runner) uint32 {
switch v.value.(type) {
case uint64:
Expand Down
8 changes: 8 additions & 0 deletions interp/testdata/consteval.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ target triple = "x86_64--linux"
@intToPtrResult = global i8 0
@ptrToIntResult = global i8 0
@icmpResult = global i8 0
@pointerTagResult = global i64 0
@someArray = internal global {i16, i8, i8} zeroinitializer
@someArrayPointer = global ptr zeroinitializer

Expand All @@ -17,6 +18,7 @@ define internal void @main.init() {
call void @testPtrToInt()
call void @testConstGEP()
call void @testICmp()
call void @testPointerTag()
ret void
}

Expand Down Expand Up @@ -63,3 +65,9 @@ unequal:
ret void
ret void
}

define internal void @testPointerTag() {
%val = and i64 ptrtoint (ptr getelementptr inbounds (i8, ptr @someArray, i32 2) to i64), 3
store i64 %val, ptr @pointerTagResult
ret void
}
1 change: 1 addition & 0 deletions interp/testdata/consteval.out.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ target triple = "x86_64--linux"
@intToPtrResult = local_unnamed_addr global i8 2
@ptrToIntResult = local_unnamed_addr global i8 2
@icmpResult = local_unnamed_addr global i8 2
@pointerTagResult = local_unnamed_addr global i64 2
@someArray = internal global { i16, i8, i8 } zeroinitializer
@someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds ({ i16, i8, i8 }, ptr @someArray, i64 0, i32 1)

Expand Down