forked from OSchip/llvm-project
114 lines
3.7 KiB
Go
114 lines
3.7 KiB
Go
//===- strings.go - IR generation for string ops --------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements IR generation for string operations.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
package irgen
|
|
|
|
import (
|
|
"go/token"
|
|
|
|
"llvm.org/llgo/third_party/gotools/go/types"
|
|
"llvm.org/llvm/bindings/go/llvm"
|
|
)
|
|
|
|
func (fr *frame) concatenateStrings(lhs, rhs *govalue) *govalue {
|
|
result := fr.runtime.stringPlus.call(fr, lhs.value, rhs.value)
|
|
return newValue(result[0], types.Typ[types.String])
|
|
}
|
|
|
|
func (fr *frame) compareStringEmpty(v llvm.Value) *govalue {
|
|
len := fr.builder.CreateExtractValue(v, 1, "")
|
|
result := fr.builder.CreateIsNull(len, "")
|
|
result = fr.builder.CreateZExt(result, llvm.Int8Type(), "")
|
|
return newValue(result, types.Typ[types.Bool])
|
|
}
|
|
|
|
func (fr *frame) compareStrings(lhs, rhs *govalue, op token.Token) *govalue {
|
|
if op == token.EQL {
|
|
if lhs.value.IsNull() {
|
|
return fr.compareStringEmpty(rhs.value)
|
|
}
|
|
if rhs.value.IsNull() {
|
|
return fr.compareStringEmpty(lhs.value)
|
|
}
|
|
}
|
|
|
|
result := fr.runtime.strcmp.call(fr, lhs.value, rhs.value)[0]
|
|
zero := llvm.ConstNull(fr.types.inttype)
|
|
var pred llvm.IntPredicate
|
|
switch op {
|
|
case token.EQL:
|
|
pred = llvm.IntEQ
|
|
case token.LSS:
|
|
pred = llvm.IntSLT
|
|
case token.GTR:
|
|
pred = llvm.IntSGT
|
|
case token.LEQ:
|
|
pred = llvm.IntSLE
|
|
case token.GEQ:
|
|
pred = llvm.IntSGE
|
|
case token.NEQ:
|
|
panic("NEQ is handled in govalue.BinaryOp")
|
|
default:
|
|
panic("unreachable")
|
|
}
|
|
result = fr.builder.CreateICmp(pred, result, zero, "")
|
|
result = fr.builder.CreateZExt(result, llvm.Int8Type(), "")
|
|
return newValue(result, types.Typ[types.Bool])
|
|
}
|
|
|
|
// stringIndex implements v = m[i]
|
|
func (fr *frame) stringIndex(s, i *govalue) *govalue {
|
|
ptr := fr.builder.CreateExtractValue(s.value, 0, "")
|
|
ptr = fr.builder.CreateGEP(ptr, []llvm.Value{i.value}, "")
|
|
return newValue(fr.builder.CreateLoad(ptr, ""), types.Typ[types.Byte])
|
|
}
|
|
|
|
func (fr *frame) stringIterInit(str *govalue) []*govalue {
|
|
indexptr := fr.allocaBuilder.CreateAlloca(fr.types.inttype, "")
|
|
fr.builder.CreateStore(llvm.ConstNull(fr.types.inttype), indexptr)
|
|
return []*govalue{str, newValue(indexptr, types.Typ[types.Int])}
|
|
}
|
|
|
|
// stringIterNext advances the iterator, and returns the tuple (ok, k, v).
|
|
func (fr *frame) stringIterNext(iter []*govalue) []*govalue {
|
|
str, indexptr := iter[0], iter[1]
|
|
k := fr.builder.CreateLoad(indexptr.value, "")
|
|
|
|
result := fr.runtime.stringiter2.call(fr, str.value, k)
|
|
fr.builder.CreateStore(result[0], indexptr.value)
|
|
ok := fr.builder.CreateIsNotNull(result[0], "")
|
|
ok = fr.builder.CreateZExt(ok, llvm.Int8Type(), "")
|
|
v := result[1]
|
|
|
|
return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, types.Typ[types.Int]), newValue(v, types.Typ[types.Rune])}
|
|
}
|
|
|
|
func (fr *frame) runeToString(v *govalue) *govalue {
|
|
v = fr.convert(v, types.Typ[types.Int])
|
|
result := fr.runtime.intToString.call(fr, v.value)
|
|
return newValue(result[0], types.Typ[types.String])
|
|
}
|
|
|
|
func (fr *frame) stringToRuneSlice(v *govalue) *govalue {
|
|
result := fr.runtime.stringToIntArray.call(fr, v.value)
|
|
runeslice := types.NewSlice(types.Typ[types.Rune])
|
|
return newValue(result[0], runeslice)
|
|
}
|
|
|
|
func (fr *frame) runeSliceToString(v *govalue) *govalue {
|
|
llv := v.value
|
|
ptr := fr.builder.CreateExtractValue(llv, 0, "")
|
|
len := fr.builder.CreateExtractValue(llv, 1, "")
|
|
result := fr.runtime.intArrayToString.call(fr, ptr, len)
|
|
return newValue(result[0], types.Typ[types.String])
|
|
}
|