Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 1 | //===- strings.go - IR generation for string ops --------------------------===// |
| 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 string operations. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | package irgen |
| 15 | |
| 16 | import ( |
| 17 | "go/token" |
Andrew Wilkins | c17d0bb | 2014-12-19 02:45:48 +0000 | [diff] [blame] | 18 | |
Peter Collingbourne | 56109b7 | 2015-01-13 20:45:08 +0000 | [diff] [blame] | 19 | "llvm.org/llgo/third_party/gotools/go/types" |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 20 | "llvm.org/llvm/bindings/go/llvm" |
| 21 | ) |
| 22 | |
| 23 | func (fr *frame) concatenateStrings(lhs, rhs *govalue) *govalue { |
| 24 | result := fr.runtime.stringPlus.call(fr, lhs.value, rhs.value) |
| 25 | return newValue(result[0], types.Typ[types.String]) |
| 26 | } |
| 27 | |
Peter Collingbourne | c5b84a5 | 2014-12-09 01:02:12 +0000 | [diff] [blame] | 28 | func (fr *frame) compareStringEmpty(v llvm.Value) *govalue { |
| 29 | len := fr.builder.CreateExtractValue(v, 1, "") |
| 30 | result := fr.builder.CreateIsNull(len, "") |
| 31 | result = fr.builder.CreateZExt(result, llvm.Int8Type(), "") |
| 32 | return newValue(result, types.Typ[types.Bool]) |
| 33 | } |
| 34 | |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 35 | func (fr *frame) compareStrings(lhs, rhs *govalue, op token.Token) *govalue { |
Peter Collingbourne | c5b84a5 | 2014-12-09 01:02:12 +0000 | [diff] [blame] | 36 | if op == token.EQL { |
| 37 | if lhs.value.IsNull() { |
| 38 | return fr.compareStringEmpty(rhs.value) |
| 39 | } |
| 40 | if rhs.value.IsNull() { |
| 41 | return fr.compareStringEmpty(lhs.value) |
| 42 | } |
| 43 | } |
| 44 | |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 45 | result := fr.runtime.strcmp.call(fr, lhs.value, rhs.value)[0] |
| 46 | zero := llvm.ConstNull(fr.types.inttype) |
| 47 | var pred llvm.IntPredicate |
| 48 | switch op { |
| 49 | case token.EQL: |
| 50 | pred = llvm.IntEQ |
| 51 | case token.LSS: |
| 52 | pred = llvm.IntSLT |
| 53 | case token.GTR: |
| 54 | pred = llvm.IntSGT |
| 55 | case token.LEQ: |
| 56 | pred = llvm.IntSLE |
| 57 | case token.GEQ: |
| 58 | pred = llvm.IntSGE |
| 59 | case token.NEQ: |
| 60 | panic("NEQ is handled in govalue.BinaryOp") |
| 61 | default: |
| 62 | panic("unreachable") |
| 63 | } |
| 64 | result = fr.builder.CreateICmp(pred, result, zero, "") |
| 65 | result = fr.builder.CreateZExt(result, llvm.Int8Type(), "") |
| 66 | return newValue(result, types.Typ[types.Bool]) |
| 67 | } |
| 68 | |
| 69 | // stringIndex implements v = m[i] |
| 70 | func (fr *frame) stringIndex(s, i *govalue) *govalue { |
| 71 | ptr := fr.builder.CreateExtractValue(s.value, 0, "") |
| 72 | ptr = fr.builder.CreateGEP(ptr, []llvm.Value{i.value}, "") |
| 73 | return newValue(fr.builder.CreateLoad(ptr, ""), types.Typ[types.Byte]) |
| 74 | } |
| 75 | |
| 76 | func (fr *frame) stringIterInit(str *govalue) []*govalue { |
| 77 | indexptr := fr.allocaBuilder.CreateAlloca(fr.types.inttype, "") |
| 78 | fr.builder.CreateStore(llvm.ConstNull(fr.types.inttype), indexptr) |
| 79 | return []*govalue{str, newValue(indexptr, types.Typ[types.Int])} |
| 80 | } |
| 81 | |
| 82 | // stringIterNext advances the iterator, and returns the tuple (ok, k, v). |
| 83 | func (fr *frame) stringIterNext(iter []*govalue) []*govalue { |
| 84 | str, indexptr := iter[0], iter[1] |
| 85 | k := fr.builder.CreateLoad(indexptr.value, "") |
| 86 | |
| 87 | result := fr.runtime.stringiter2.call(fr, str.value, k) |
| 88 | fr.builder.CreateStore(result[0], indexptr.value) |
| 89 | ok := fr.builder.CreateIsNotNull(result[0], "") |
| 90 | ok = fr.builder.CreateZExt(ok, llvm.Int8Type(), "") |
| 91 | v := result[1] |
| 92 | |
| 93 | return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, types.Typ[types.Int]), newValue(v, types.Typ[types.Rune])} |
| 94 | } |
| 95 | |
| 96 | func (fr *frame) runeToString(v *govalue) *govalue { |
| 97 | v = fr.convert(v, types.Typ[types.Int]) |
| 98 | result := fr.runtime.intToString.call(fr, v.value) |
| 99 | return newValue(result[0], types.Typ[types.String]) |
| 100 | } |
| 101 | |
| 102 | func (fr *frame) stringToRuneSlice(v *govalue) *govalue { |
| 103 | result := fr.runtime.stringToIntArray.call(fr, v.value) |
| 104 | runeslice := types.NewSlice(types.Typ[types.Rune]) |
| 105 | return newValue(result[0], runeslice) |
| 106 | } |
| 107 | |
| 108 | func (fr *frame) runeSliceToString(v *govalue) *govalue { |
| 109 | llv := v.value |
| 110 | ptr := fr.builder.CreateExtractValue(llv, 0, "") |
| 111 | len := fr.builder.CreateExtractValue(llv, 1, "") |
| 112 | result := fr.runtime.intArrayToString.call(fr, ptr, len) |
| 113 | return newValue(result[0], types.Typ[types.String]) |
| 114 | } |