115 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
| //===- strings.go - IR generation for string ops --------------------------===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // 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])
 | |
| }
 |