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 }