github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/irgen/maps.go (about)

     1  //===- maps.go - IR generation for maps -----------------------------------===//
     2  //
     3  //                     The LLVM Compiler Infrastructure
     4  //
     5  // This file is distributed under the University of Illinois Open Source
     6  // License. See LICENSE.TXT for details.
     7  //
     8  //===----------------------------------------------------------------------===//
     9  //
    10  // This file implements IR generation for maps.
    11  //
    12  //===----------------------------------------------------------------------===//
    13  
    14  package irgen
    15  
    16  import (
    17  	"llvm.org/llgo/third_party/gotools/go/types"
    18  	"llvm.org/llvm/bindings/go/llvm"
    19  )
    20  
    21  // makeMap implements make(maptype[, initial space])
    22  func (fr *frame) makeMap(typ types.Type, cap_ *govalue) *govalue {
    23  	// TODO(pcc): call __go_new_map_big here if needed
    24  	dyntyp := fr.types.getMapDescriptorPointer(typ)
    25  	dyntyp = fr.builder.CreateBitCast(dyntyp, llvm.PointerType(llvm.Int8Type(), 0), "")
    26  	var cap llvm.Value
    27  	if cap_ != nil {
    28  		cap = fr.convert(cap_, types.Typ[types.Uintptr]).value
    29  	} else {
    30  		cap = llvm.ConstNull(fr.types.inttype)
    31  	}
    32  	m := fr.runtime.newMap.call(fr, dyntyp, cap)
    33  	return newValue(m[0], typ)
    34  }
    35  
    36  // mapLookup implements v[, ok] = m[k]
    37  func (fr *frame) mapLookup(m, k *govalue) (v *govalue, ok *govalue) {
    38  	llk := k.value
    39  	pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "")
    40  	fr.builder.CreateStore(llk, pk)
    41  	valptr := fr.runtime.mapIndex.call(fr, m.value, pk, boolLLVMValue(false))[0]
    42  	valptr.AddInstrAttribute(2, llvm.NoCaptureAttribute)
    43  	valptr.AddInstrAttribute(2, llvm.ReadOnlyAttribute)
    44  	okbit := fr.builder.CreateIsNotNull(valptr, "")
    45  
    46  	elemtyp := m.Type().Underlying().(*types.Map).Elem()
    47  	ok = newValue(fr.builder.CreateZExt(okbit, llvm.Int8Type(), ""), types.Typ[types.Bool])
    48  	v = fr.loadOrNull(okbit, valptr, elemtyp)
    49  	return
    50  }
    51  
    52  // mapUpdate implements m[k] = v
    53  func (fr *frame) mapUpdate(m, k, v *govalue) {
    54  	llk := k.value
    55  	pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "")
    56  	fr.builder.CreateStore(llk, pk)
    57  	valptr := fr.runtime.mapIndex.call(fr, m.value, pk, boolLLVMValue(true))[0]
    58  	valptr.AddInstrAttribute(2, llvm.NoCaptureAttribute)
    59  	valptr.AddInstrAttribute(2, llvm.ReadOnlyAttribute)
    60  
    61  	elemtyp := m.Type().Underlying().(*types.Map).Elem()
    62  	llelemtyp := fr.types.ToLLVM(elemtyp)
    63  	typedvalptr := fr.builder.CreateBitCast(valptr, llvm.PointerType(llelemtyp, 0), "")
    64  	fr.builder.CreateStore(v.value, typedvalptr)
    65  }
    66  
    67  // mapDelete implements delete(m, k)
    68  func (fr *frame) mapDelete(m, k *govalue) {
    69  	llk := k.value
    70  	pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "")
    71  	fr.builder.CreateStore(llk, pk)
    72  	fr.runtime.mapdelete.call(fr, m.value, pk)
    73  }
    74  
    75  // mapIterInit creates a map iterator
    76  func (fr *frame) mapIterInit(m *govalue) []*govalue {
    77  	// We represent an iterator as a tuple (map, *bool). The second element
    78  	// controls whether the code we generate for "next" (below) calls the
    79  	// runtime function for the first or the next element. We let the
    80  	// optimizer reorganize this into something more sensible.
    81  	isinit := fr.allocaBuilder.CreateAlloca(llvm.Int1Type(), "")
    82  	fr.builder.CreateStore(llvm.ConstNull(llvm.Int1Type()), isinit)
    83  
    84  	return []*govalue{m, newValue(isinit, types.NewPointer(types.Typ[types.Bool]))}
    85  }
    86  
    87  // mapIterNext advances the iterator, and returns the tuple (ok, k, v).
    88  func (fr *frame) mapIterNext(iter []*govalue) []*govalue {
    89  	maptyp := iter[0].Type().Underlying().(*types.Map)
    90  	ktyp := maptyp.Key()
    91  	klltyp := fr.types.ToLLVM(ktyp)
    92  	vtyp := maptyp.Elem()
    93  	vlltyp := fr.types.ToLLVM(vtyp)
    94  
    95  	m, isinitptr := iter[0], iter[1]
    96  
    97  	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
    98  	mapiterbufty := llvm.ArrayType(i8ptr, 4)
    99  	mapiterbuf := fr.allocaBuilder.CreateAlloca(mapiterbufty, "")
   100  	mapiterbufelem0ptr := fr.builder.CreateStructGEP(mapiterbuf, 0, "")
   101  
   102  	keybuf := fr.allocaBuilder.CreateAlloca(klltyp, "")
   103  	keyptr := fr.builder.CreateBitCast(keybuf, i8ptr, "")
   104  	valbuf := fr.allocaBuilder.CreateAlloca(vlltyp, "")
   105  	valptr := fr.builder.CreateBitCast(valbuf, i8ptr, "")
   106  
   107  	isinit := fr.builder.CreateLoad(isinitptr.value, "")
   108  
   109  	initbb := llvm.AddBasicBlock(fr.function, "")
   110  	nextbb := llvm.AddBasicBlock(fr.function, "")
   111  	contbb := llvm.AddBasicBlock(fr.function, "")
   112  
   113  	fr.builder.CreateCondBr(isinit, nextbb, initbb)
   114  
   115  	fr.builder.SetInsertPointAtEnd(initbb)
   116  	fr.builder.CreateStore(llvm.ConstAllOnes(llvm.Int1Type()), isinitptr.value)
   117  	fr.runtime.mapiterinit.call(fr, m.value, mapiterbufelem0ptr)
   118  	fr.builder.CreateBr(contbb)
   119  
   120  	fr.builder.SetInsertPointAtEnd(nextbb)
   121  	fr.runtime.mapiternext.call(fr, mapiterbufelem0ptr)
   122  	fr.builder.CreateBr(contbb)
   123  
   124  	fr.builder.SetInsertPointAtEnd(contbb)
   125  	mapiterbufelem0 := fr.builder.CreateLoad(mapiterbufelem0ptr, "")
   126  	okbit := fr.builder.CreateIsNotNull(mapiterbufelem0, "")
   127  	ok := fr.builder.CreateZExt(okbit, llvm.Int8Type(), "")
   128  
   129  	loadbb := llvm.AddBasicBlock(fr.function, "")
   130  	cont2bb := llvm.AddBasicBlock(fr.function, "")
   131  	fr.builder.CreateCondBr(okbit, loadbb, cont2bb)
   132  
   133  	fr.builder.SetInsertPointAtEnd(loadbb)
   134  	fr.runtime.mapiter2.call(fr, mapiterbufelem0ptr, keyptr, valptr)
   135  	loadbb = fr.builder.GetInsertBlock()
   136  	loadedkey := fr.builder.CreateLoad(keybuf, "")
   137  	loadedval := fr.builder.CreateLoad(valbuf, "")
   138  	fr.builder.CreateBr(cont2bb)
   139  
   140  	fr.builder.SetInsertPointAtEnd(cont2bb)
   141  	k := fr.builder.CreatePHI(klltyp, "")
   142  	k.AddIncoming(
   143  		[]llvm.Value{llvm.ConstNull(klltyp), loadedkey},
   144  		[]llvm.BasicBlock{contbb, loadbb},
   145  	)
   146  	v := fr.builder.CreatePHI(vlltyp, "")
   147  	v.AddIncoming(
   148  		[]llvm.Value{llvm.ConstNull(vlltyp), loadedval},
   149  		[]llvm.BasicBlock{contbb, loadbb},
   150  	)
   151  
   152  	return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, ktyp), newValue(v, vtyp)}
   153  }