Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 | [diff] [blame] | 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 ( |
Peter Collingbourne | 56109b7 | 2015-01-13 20:45:08 | [diff] [blame] | 17 | "llvm.org/llgo/third_party/gotools/go/types" |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 | [diff] [blame] | 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] |
Meador Inge | 21e5350 | 2016-12-06 04:01:11 | [diff] [blame] | 42 | attrkind := llvm.AttributeKindID("nocapture") |
| 43 | valptr.AddCallSiteAttribute(2, fr.types.ctx.CreateEnumAttribute(attrkind, 0)) |
| 44 | attrkind = llvm.AttributeKindID("readonly") |
| 45 | valptr.AddCallSiteAttribute(2, fr.types.ctx.CreateEnumAttribute(attrkind, 0)) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 | [diff] [blame] | 46 | okbit := fr.builder.CreateIsNotNull(valptr, "") |
| 47 | |
| 48 | elemtyp := m.Type().Underlying().(*types.Map).Elem() |
| 49 | ok = newValue(fr.builder.CreateZExt(okbit, llvm.Int8Type(), ""), types.Typ[types.Bool]) |
| 50 | v = fr.loadOrNull(okbit, valptr, elemtyp) |
| 51 | return |
| 52 | } |
| 53 | |
| 54 | // mapUpdate implements m[k] = v |
| 55 | func (fr *frame) mapUpdate(m, k, v *govalue) { |
| 56 | llk := k.value |
| 57 | pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "") |
| 58 | fr.builder.CreateStore(llk, pk) |
| 59 | valptr := fr.runtime.mapIndex.call(fr, m.value, pk, boolLLVMValue(true))[0] |
Meador Inge | 21e5350 | 2016-12-06 04:01:11 | [diff] [blame] | 60 | attrkind := llvm.AttributeKindID("nocapture") |
| 61 | valptr.AddCallSiteAttribute(2, fr.types.ctx.CreateEnumAttribute(attrkind, 0)) |
| 62 | attrkind = llvm.AttributeKindID("readonly") |
| 63 | valptr.AddCallSiteAttribute(2, fr.types.ctx.CreateEnumAttribute(attrkind, 0)) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 | [diff] [blame] | 64 | |
| 65 | elemtyp := m.Type().Underlying().(*types.Map).Elem() |
| 66 | llelemtyp := fr.types.ToLLVM(elemtyp) |
| 67 | typedvalptr := fr.builder.CreateBitCast(valptr, llvm.PointerType(llelemtyp, 0), "") |
| 68 | fr.builder.CreateStore(v.value, typedvalptr) |
| 69 | } |
| 70 | |
| 71 | // mapDelete implements delete(m, k) |
| 72 | func (fr *frame) mapDelete(m, k *govalue) { |
| 73 | llk := k.value |
| 74 | pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "") |
| 75 | fr.builder.CreateStore(llk, pk) |
| 76 | fr.runtime.mapdelete.call(fr, m.value, pk) |
| 77 | } |
| 78 | |
| 79 | // mapIterInit creates a map iterator |
| 80 | func (fr *frame) mapIterInit(m *govalue) []*govalue { |
| 81 | // We represent an iterator as a tuple (map, *bool). The second element |
| 82 | // controls whether the code we generate for "next" (below) calls the |
| 83 | // runtime function for the first or the next element. We let the |
| 84 | // optimizer reorganize this into something more sensible. |
| 85 | isinit := fr.allocaBuilder.CreateAlloca(llvm.Int1Type(), "") |
| 86 | fr.builder.CreateStore(llvm.ConstNull(llvm.Int1Type()), isinit) |
| 87 | |
| 88 | return []*govalue{m, newValue(isinit, types.NewPointer(types.Typ[types.Bool]))} |
| 89 | } |
| 90 | |
| 91 | // mapIterNext advances the iterator, and returns the tuple (ok, k, v). |
| 92 | func (fr *frame) mapIterNext(iter []*govalue) []*govalue { |
| 93 | maptyp := iter[0].Type().Underlying().(*types.Map) |
| 94 | ktyp := maptyp.Key() |
| 95 | klltyp := fr.types.ToLLVM(ktyp) |
| 96 | vtyp := maptyp.Elem() |
| 97 | vlltyp := fr.types.ToLLVM(vtyp) |
| 98 | |
| 99 | m, isinitptr := iter[0], iter[1] |
| 100 | |
| 101 | i8ptr := llvm.PointerType(llvm.Int8Type(), 0) |
| 102 | mapiterbufty := llvm.ArrayType(i8ptr, 4) |
| 103 | mapiterbuf := fr.allocaBuilder.CreateAlloca(mapiterbufty, "") |
| 104 | mapiterbufelem0ptr := fr.builder.CreateStructGEP(mapiterbuf, 0, "") |
| 105 | |
| 106 | keybuf := fr.allocaBuilder.CreateAlloca(klltyp, "") |
| 107 | keyptr := fr.builder.CreateBitCast(keybuf, i8ptr, "") |
| 108 | valbuf := fr.allocaBuilder.CreateAlloca(vlltyp, "") |
| 109 | valptr := fr.builder.CreateBitCast(valbuf, i8ptr, "") |
| 110 | |
| 111 | isinit := fr.builder.CreateLoad(isinitptr.value, "") |
| 112 | |
| 113 | initbb := llvm.AddBasicBlock(fr.function, "") |
| 114 | nextbb := llvm.AddBasicBlock(fr.function, "") |
| 115 | contbb := llvm.AddBasicBlock(fr.function, "") |
| 116 | |
| 117 | fr.builder.CreateCondBr(isinit, nextbb, initbb) |
| 118 | |
| 119 | fr.builder.SetInsertPointAtEnd(initbb) |
| 120 | fr.builder.CreateStore(llvm.ConstAllOnes(llvm.Int1Type()), isinitptr.value) |
| 121 | fr.runtime.mapiterinit.call(fr, m.value, mapiterbufelem0ptr) |
| 122 | fr.builder.CreateBr(contbb) |
| 123 | |
| 124 | fr.builder.SetInsertPointAtEnd(nextbb) |
| 125 | fr.runtime.mapiternext.call(fr, mapiterbufelem0ptr) |
| 126 | fr.builder.CreateBr(contbb) |
| 127 | |
| 128 | fr.builder.SetInsertPointAtEnd(contbb) |
| 129 | mapiterbufelem0 := fr.builder.CreateLoad(mapiterbufelem0ptr, "") |
| 130 | okbit := fr.builder.CreateIsNotNull(mapiterbufelem0, "") |
| 131 | ok := fr.builder.CreateZExt(okbit, llvm.Int8Type(), "") |
| 132 | |
| 133 | loadbb := llvm.AddBasicBlock(fr.function, "") |
| 134 | cont2bb := llvm.AddBasicBlock(fr.function, "") |
| 135 | fr.builder.CreateCondBr(okbit, loadbb, cont2bb) |
| 136 | |
| 137 | fr.builder.SetInsertPointAtEnd(loadbb) |
| 138 | fr.runtime.mapiter2.call(fr, mapiterbufelem0ptr, keyptr, valptr) |
| 139 | loadbb = fr.builder.GetInsertBlock() |
| 140 | loadedkey := fr.builder.CreateLoad(keybuf, "") |
| 141 | loadedval := fr.builder.CreateLoad(valbuf, "") |
| 142 | fr.builder.CreateBr(cont2bb) |
| 143 | |
| 144 | fr.builder.SetInsertPointAtEnd(cont2bb) |
| 145 | k := fr.builder.CreatePHI(klltyp, "") |
| 146 | k.AddIncoming( |
| 147 | []llvm.Value{llvm.ConstNull(klltyp), loadedkey}, |
| 148 | []llvm.BasicBlock{contbb, loadbb}, |
| 149 | ) |
| 150 | v := fr.builder.CreatePHI(vlltyp, "") |
| 151 | v.AddIncoming( |
| 152 | []llvm.Value{llvm.ConstNull(vlltyp), loadedval}, |
| 153 | []llvm.BasicBlock{contbb, loadbb}, |
| 154 | ) |
| 155 | |
| 156 | return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, ktyp), newValue(v, vtyp)} |
| 157 | } |