blob: 6e153969a225afc9afa5d41498e15933677e2e51 [file] [log] [blame]
Peter Collingbournead9841e2014-11-27 00:06:421//===- 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
14package irgen
15
16import (
Peter Collingbourne56109b72015-01-13 20:45:0817 "llvm.org/llgo/third_party/gotools/go/types"
Peter Collingbournead9841e2014-11-27 00:06:4218 "llvm.org/llvm/bindings/go/llvm"
19)
20
21// makeMap implements make(maptype[, initial space])
22func (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]
37func (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 Inge21e53502016-12-06 04:01:1142 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 Collingbournead9841e2014-11-27 00:06:4246 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
55func (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 Inge21e53502016-12-06 04:01:1160 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 Collingbournead9841e2014-11-27 00:06:4264
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)
72func (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
80func (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).
92func (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}