Skip to content

Commit

Permalink
Implement Range (maps only) and delete
Browse files Browse the repository at this point in the history
Also, fix stacksave/stackrestore (can't wrap, duh).
  • Loading branch information
axw committed Nov 11, 2013
1 parent 061c9d4 commit 5ca34b6
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 94 deletions.
94 changes: 79 additions & 15 deletions maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@ func (c *compiler) mapLookup(m, k *LLVMValue, commaOk bool) *LLVMValue {
dyntyp := c.types.ToRuntime(m.Type())
dyntyp = c.builder.CreatePtrToInt(dyntyp, c.target.IntPtrType(), "")

defer c.stackrestore(c.stacksave())
stackptr := c.stacksave()
llk := k.LLVMValue()
pk := c.builder.CreateAlloca(llk.Type(), "")
c.builder.CreateStore(llk, pk)
elemtyp := m.Type().Underlying().(*types.Map).Elem()
pv := c.builder.CreateAlloca(c.types.ToLLVM(elemtyp), "")

ok := c.builder.CreateCall(
c.runtime.mapaccess.LLVMValue(),
[]llvm.Value{
Expand All @@ -45,11 +44,12 @@ func (c *compiler) mapLookup(m, k *LLVMValue, commaOk bool) *LLVMValue {
c.builder.CreatePtrToInt(pv, c.target.IntPtrType(), ""),
}, "",
)

v := c.builder.CreateLoad(pv, "")
c.stackrestore(stackptr)
if !commaOk {
return c.NewValue(v, elemtyp)
}

fields := []*types.Var{
types.NewParam(0, nil, "", elemtyp),
types.NewParam(0, nil, "", types.Typ[types.Bool]),
Expand All @@ -61,30 +61,94 @@ func (c *compiler) mapLookup(m, k *LLVMValue, commaOk bool) *LLVMValue {
return c.NewValue(tuple, typ)
}

// mapSlot gets a pointer to the m[k] value slot; if insert is true
// and the key does not exist, it is inserted.
func (c *compiler) mapSlot(m_, k_ *LLVMValue, insert_ bool) *LLVMValue {
// mapUpdate implements m[k] = v
func (c *compiler) mapUpdate(m_, k_, v_ *LLVMValue) {
f := c.runtime.maplookup.LLVMValue()
dyntyp := c.types.ToRuntime(m_.Type())
dyntyp = c.builder.CreatePtrToInt(dyntyp, c.target.IntPtrType(), "")
m := m_.LLVMValue()
k := k_.LLVMValue()

// FIXME require that k is a pointer
defer c.stackrestore(c.stacksave())
stackptr := c.stacksave()
pk := c.builder.CreateAlloca(k.Type(), "")
c.builder.CreateStore(k, pk)
pk = c.builder.CreatePtrToInt(pk, c.target.IntPtrType(), "")

insert := boolLLVMValue(insert_)
insert := boolLLVMValue(true)
ptrv := c.builder.CreateCall(f, []llvm.Value{dyntyp, m, pk, insert}, "")
c.stackrestore(stackptr)

ptrvtyp := types.NewPointer(m_.Type().Underlying().(*types.Map).Elem())
ptrv = c.builder.CreateIntToPtr(ptrv, c.types.ToLLVM(ptrvtyp), "")
return c.NewValue(ptrv, ptrvtyp)
c.builder.CreateStore(v_.LLVMValue(), ptrv)
}

// mapUpdate implements m[k] = v
func (c *compiler) mapUpdate(m, k, v *LLVMValue) {
ptrv := c.mapSlot(m, k, true)
c.builder.CreateStore(v.LLVMValue(), ptrv.LLVMValue())
// mapDelete implements delete(m, k)
func (c *compiler) mapDelete(m_, k_ *LLVMValue) {
f := c.runtime.mapdelete.LLVMValue()
dyntyp := c.types.ToRuntime(m_.Type())
dyntyp = c.builder.CreatePtrToInt(dyntyp, c.target.IntPtrType(), "")
m := m_.LLVMValue()
k := k_.LLVMValue()
stackptr := c.stacksave()
pk := c.builder.CreateAlloca(k.Type(), "")
c.builder.CreateStore(k, pk)
pk = c.builder.CreatePtrToInt(pk, c.target.IntPtrType(), "")
c.builder.CreateCall(f, []llvm.Value{dyntyp, m, pk}, "")
c.stackrestore(stackptr)
}

// mapIterInit creates a map iterator
func (c *compiler) mapIterInit(m *LLVMValue) *LLVMValue {
// TODO allocate iterator on stack at usage site
f := c.runtime.mapiterinit.LLVMValue()
dyntyp := c.types.ToRuntime(m.Type())
iter := c.builder.CreateCall(f, []llvm.Value{
c.builder.CreatePtrToInt(dyntyp, c.target.IntPtrType(), ""),
c.builder.CreatePtrToInt(m.LLVMValue(), c.target.IntPtrType(), ""),
}, "")
return c.NewValue(iter, m.Type())
}

// mapIterNext advances the iterator, and returns the tuple (ok, k, v).
func (c *compiler) mapIterNext(iter *LLVMValue) *LLVMValue {
maptyp := iter.Type().Underlying().(*types.Map)
ktyp := maptyp.Key()
vtyp := maptyp.Elem()

lliter := iter.LLVMValue()
mapiternext := c.runtime.mapiternext.LLVMValue()
ok := c.builder.CreateCall(mapiternext, []llvm.Value{lliter}, "")

fields := []*types.Var{
types.NewParam(0, nil, "", types.Typ[types.Bool]),
types.NewParam(0, nil, "", ktyp),
types.NewParam(0, nil, "", vtyp),
}
typ := types.NewStruct(fields, nil)
tuple := llvm.Undef(c.types.ToLLVM(typ))
tuple = c.builder.CreateInsertValue(tuple, ok, 0, "")

currBlock := c.builder.GetInsertBlock()
endBlock := llvm.InsertBasicBlock(currBlock, "")
endBlock.MoveAfter(currBlock)
okBlock := llvm.InsertBasicBlock(endBlock, "")
c.builder.CreateCondBr(ok, okBlock, endBlock)

// TODO when mapIterInit/mapIterNext operate on a
// stack-allocated struct, use CreateExtractValue
// to load pk/pv.
c.builder.SetInsertPointAtEnd(okBlock)
lliter = c.builder.CreateIntToPtr(lliter, llvm.PointerType(c.runtime.mapiter.llvm, 0), "")
pk := c.builder.CreateLoad(c.builder.CreateStructGEP(lliter, 0, ""), "")
pv := c.builder.CreateLoad(c.builder.CreateStructGEP(lliter, 1, ""), "")
k := c.builder.CreateLoad(c.builder.CreateIntToPtr(pk, llvm.PointerType(c.types.ToLLVM(ktyp), 0), ""), "")
v := c.builder.CreateLoad(c.builder.CreateIntToPtr(pv, llvm.PointerType(c.types.ToLLVM(vtyp), 0), ""), "")
tuplekv := c.builder.CreateInsertValue(tuple, k, 1, "")
tuplekv = c.builder.CreateInsertValue(tuplekv, v, 2, "")
c.builder.CreateBr(endBlock)

c.builder.SetInsertPointAtEnd(endBlock)
phi := c.builder.CreatePHI(tuple.Type(), "")
phi.AddIncoming([]llvm.Value{tuple, tuplekv}, []llvm.BasicBlock{currBlock, okBlock})
return c.NewValue(phi, typ)
}
93 changes: 49 additions & 44 deletions pkg/runtime/maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@ package runtime

import "unsafe"

type map_ struct {
length int32
head *mapentry
}
type map_ []*mapentry

type mapentry struct {
next *mapentry
// after this comes the key, then the value.
// first comes the key, then the value.
}

// #llgo name: reflect.ismapkey
Expand All @@ -39,7 +35,7 @@ func reflect_maplen(m unsafe.Pointer) int32 {

func maplen(m unsafe.Pointer) int {
if m != nil {
return int((*map_)(m).length)
return len(*(*map_)(m))
}
return 0
}
Expand Down Expand Up @@ -83,7 +79,7 @@ func maplookup(t unsafe.Pointer, m_, key unsafe.Pointer, insert bool) unsafe.Poi
m := (*map_)(m_)

maptyp := (*mapType)(t)
ptrsize := uintptr(unsafe.Sizeof(m.head.next))
ptrsize := uintptr(unsafe.Sizeof(m_))
keysize := uintptr(maptyp.key.size)
keyoffset := align(ptrsize, uintptr(maptyp.key.align))
elemsize := uintptr(maptyp.elem.size)
Expand All @@ -94,29 +90,22 @@ func maplookup(t unsafe.Pointer, m_, key unsafe.Pointer, insert bool) unsafe.Poi
keyalgs := unsafe.Pointer(maptyp.key.alg)
keyeqptr := unsafe.Pointer(uintptr(keyalgs) + unsafe.Sizeof(maptyp.key.alg))
keyeqfun := *(*unsafe.Pointer)(keyeqptr)
var last *mapentry
for ptr := m.head; ptr != nil; ptr = ptr.next {
for i := 0; i < len(*m); i++ {
ptr := (*m)[i]
keyptr := unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + keyoffset)
if eqalg(keyeqfun, keysize, key, keyptr) {
elemptr := unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + elemoffset)
return elemptr
}
last = ptr
}

// Not found: insert the key if requested.
if insert {
newentry := (*mapentry)(malloc(entrysize))
newentry.next = nil
keyptr := unsafe.Pointer(uintptr(unsafe.Pointer(newentry)) + keyoffset)
elemptr := unsafe.Pointer(uintptr(unsafe.Pointer(newentry)) + elemoffset)
memcpy(keyptr, key, keysize)
if last != nil {
last.next = newentry
} else {
m.head = newentry
}
m.length++
*m = append(*m, newentry)
return elemptr
}

Expand All @@ -130,28 +119,26 @@ func mapdelete(t unsafe.Pointer, m_, key unsafe.Pointer) {
m := (*map_)(m_)

maptyp := (*mapType)(t)
ptrsize := uintptr(unsafe.Sizeof(m.head.next))
ptrsize := uintptr(unsafe.Sizeof(m_))
keysize := uintptr(maptyp.key.size)
keyoffset := align(ptrsize, uintptr(maptyp.key.align))

// Search for the entry with the specified key.
keyalgs := unsafe.Pointer(maptyp.key.alg)
keyeqptr := unsafe.Pointer(uintptr(keyalgs) + unsafe.Sizeof(maptyp.key.alg))
keyeqfun := *(*unsafe.Pointer)(keyeqptr)
var last *mapentry
for ptr := m.head; ptr != nil; ptr = ptr.next {
for i := 0; i < len(*m); i++ {
ptr := (*m)[i]
keyptr := unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + keyoffset)
if eqalg(keyeqfun, keysize, key, keyptr) {
if last == nil {
m.head = ptr.next
} else {
last.next = ptr.next
var tail []*mapentry
if len(*m) > i+1 {
tail = (*m)[i+1:]
}
(*m) = append((*m)[:i], tail...)
free(unsafe.Pointer(ptr))
m.length--
return
}
last = ptr
}
}

Expand All @@ -172,25 +159,43 @@ func reflect_mapiternext(it *byte) {
// TODO
}

func mapnext(t unsafe.Pointer, m *map_, nextin unsafe.Pointer) (nextout, pk, pv unsafe.Pointer) {
type mapiter struct {
ptrk unsafe.Pointer
ptrv unsafe.Pointer

typ *mapType
m *map_
i int
}

// TODO pass pointer to stack allocated block in
func mapiterinit(t, m unsafe.Pointer) unsafe.Pointer {
if m == nil {
return
return nil
}
ptr := (*mapentry)(nextin)
if ptr == nil {
ptr = m.head
} else {
ptr = ptr.next
iter := (*mapiter)(malloc(unsafe.Sizeof(mapiter{})))
iter.typ = (*mapType)(t)
iter.m = (*map_)(m)
return unsafe.Pointer(iter)
}

func mapiternext(iter_ unsafe.Pointer) bool {
if iter_ == nil {
return false
}
if ptr != nil {
maptyp := (*mapType)(t)
ptrsize := uintptr(unsafe.Sizeof(m.head.next))
keysize := uintptr(maptyp.key.size)
keyoffset := align(ptrsize, uintptr(maptyp.key.align))
elemoffset := align(keyoffset+keysize, uintptr(maptyp.elem.align))
nextout = unsafe.Pointer(ptr)
pk = unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + keyoffset)
pv = unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + elemoffset)
iter := (*mapiter)(iter_)
if iter.i >= len(*iter.m) {
iter.ptrk = nil
iter.ptrv = nil
return false
}
return
entry := (*iter.m)[iter.i]
iter.i++
ptrsize := uintptr(unsafe.Sizeof(entry))
keysize := uintptr(iter.typ.key.size)
keyoffset := align(ptrsize, uintptr(iter.typ.key.align))
elemoffset := align(keyoffset+keysize, uintptr(iter.typ.elem.align))
iter.ptrk = unsafe.Pointer(uintptr(unsafe.Pointer(entry)) + keyoffset)
iter.ptrv = unsafe.Pointer(uintptr(unsafe.Pointer(entry)) + elemoffset)
return true
}
2 changes: 0 additions & 2 deletions pkg/runtime/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ func free(unsafe.Pointer)
func memcpy(dst, src unsafe.Pointer, size uintptr)
func memmove(dst, src unsafe.Pointer, size uintptr)
func memset(dst unsafe.Pointer, fill byte, size uintptr)
func stacksave() *int8
func stackrestore(*int8)

func bzero(dst unsafe.Pointer, size uintptr) {
memset(dst, 0, size)
Expand Down
14 changes: 0 additions & 14 deletions pkg/runtime/memory.ll
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ declare void @free(i8*)
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind
declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind
declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind
declare void @llvm.stackrestore(i8*)
declare i8* @llvm.stacksave()

define void @runtime.free(i64) {
entry:
Expand Down Expand Up @@ -38,15 +36,3 @@ entry:
call void @llvm.memset.p0i8.i64(i8* %3, i8 %1, i64 %2, i32 1, i1 false)
ret void
}

define void @runtime.stackrestore(i8*) {
entry:
call void @llvm.stackrestore(i8* %0)
ret void
}

define i8* @runtime.stacksave() {
entry:
%0 = call i8* @llvm.stacksave()
ret i8* %0
}
14 changes: 10 additions & 4 deletions println.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
package llgo

import (
"code.google.com/p/go.tools/go/types"
"fmt"

"code.google.com/p/go.tools/go/exact"
"code.google.com/p/go.tools/go/types"
"github.com/axw/gollvm/llvm"
)

Expand Down Expand Up @@ -54,7 +56,7 @@ func (c *compiler) getBoolString(v llvm.Value) llvm.Value {
return result
}

func (c *compiler) printValues(println_ bool, values ...Value) Value {
func (c *compiler) printValues(println_ bool, values ...Value) {
var args []llvm.Value = nil
if len(values) > 0 {
format := ""
Expand Down Expand Up @@ -156,9 +158,13 @@ func (c *compiler) printValues(println_ bool, values ...Value) Value {
args = []llvm.Value{c.builder.CreateGlobalStringPtr(format, "")}
}
printf := getPrintf(c.module.Module)
result := c.NewValue(c.builder.CreateCall(printf, args, ""), types.Typ[types.Int32])
c.NewValue(c.builder.CreateCall(printf, args, ""), types.Typ[types.Int32])
fflush := getFflush(c.module.Module)
fileptr := llvm.ConstNull(fflush.Type().ElementType().ParamTypes()[0])
c.builder.CreateCall(fflush, []llvm.Value{fileptr}, "")
return result
}

func (c *compiler) printf(format string, args ...interface{}) {
s := exact.MakeString(fmt.Sprintf(format, args...))
c.printValues(true, c.NewConstValue(s, types.Typ[types.String]))
}
Loading

0 comments on commit 5ca34b6

Please sign in to comment.