forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			135 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
//===- channels.go - IR generation for channels ---------------------------===//
 | 
						|
//
 | 
						|
//                     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 channels.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
package irgen
 | 
						|
 | 
						|
import (
 | 
						|
	"llvm.org/llgo/third_party/gotools/go/ssa"
 | 
						|
	"llvm.org/llgo/third_party/gotools/go/types"
 | 
						|
	"llvm.org/llvm/bindings/go/llvm"
 | 
						|
)
 | 
						|
 | 
						|
// makeChan implements make(chantype[, size])
 | 
						|
func (fr *frame) makeChan(chantyp types.Type, size *govalue) *govalue {
 | 
						|
	// TODO(pcc): call __go_new_channel_big here if needed
 | 
						|
	dyntyp := fr.types.ToRuntime(chantyp)
 | 
						|
	size = fr.convert(size, types.Typ[types.Uintptr])
 | 
						|
	ch := fr.runtime.newChannel.call(fr, dyntyp, size.value)[0]
 | 
						|
	return newValue(ch, chantyp)
 | 
						|
}
 | 
						|
 | 
						|
// chanSend implements ch<- x
 | 
						|
func (fr *frame) chanSend(ch *govalue, elem *govalue) {
 | 
						|
	elemtyp := ch.Type().Underlying().(*types.Chan).Elem()
 | 
						|
	elem = fr.convert(elem, elemtyp)
 | 
						|
	elemptr := fr.allocaBuilder.CreateAlloca(elem.value.Type(), "")
 | 
						|
	fr.builder.CreateStore(elem.value, elemptr)
 | 
						|
	elemptr = fr.builder.CreateBitCast(elemptr, llvm.PointerType(llvm.Int8Type(), 0), "")
 | 
						|
	chantyp := fr.types.ToRuntime(ch.Type())
 | 
						|
	fr.runtime.sendBig.call(fr, chantyp, ch.value, elemptr)
 | 
						|
}
 | 
						|
 | 
						|
// chanRecv implements x[, ok] = <-ch
 | 
						|
func (fr *frame) chanRecv(ch *govalue, commaOk bool) (x, ok *govalue) {
 | 
						|
	elemtyp := ch.Type().Underlying().(*types.Chan).Elem()
 | 
						|
	ptr := fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(elemtyp), "")
 | 
						|
	ptri8 := fr.builder.CreateBitCast(ptr, llvm.PointerType(llvm.Int8Type(), 0), "")
 | 
						|
	chantyp := fr.types.ToRuntime(ch.Type())
 | 
						|
 | 
						|
	if commaOk {
 | 
						|
		okval := fr.runtime.chanrecv2.call(fr, chantyp, ch.value, ptri8)[0]
 | 
						|
		ok = newValue(okval, types.Typ[types.Bool])
 | 
						|
	} else {
 | 
						|
		fr.runtime.receive.call(fr, chantyp, ch.value, ptri8)
 | 
						|
	}
 | 
						|
	x = newValue(fr.builder.CreateLoad(ptr, ""), elemtyp)
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// chanClose implements close(ch)
 | 
						|
func (fr *frame) chanClose(ch *govalue) {
 | 
						|
	fr.runtime.builtinClose.call(fr, ch.value)
 | 
						|
}
 | 
						|
 | 
						|
func (fr *frame) chanSelect(sel *ssa.Select) (index, recvOk *govalue, recvElems []*govalue) {
 | 
						|
	n := uint64(len(sel.States))
 | 
						|
	if !sel.Blocking {
 | 
						|
		// non-blocking means there's a default case
 | 
						|
		n++
 | 
						|
	}
 | 
						|
	size := llvm.ConstInt(llvm.Int32Type(), n, false)
 | 
						|
	selectp := fr.runtime.newSelect.call(fr, size)[0]
 | 
						|
 | 
						|
	// Allocate stack for the values to send and receive.
 | 
						|
	ptrs := make([]llvm.Value, len(sel.States))
 | 
						|
	for i, state := range sel.States {
 | 
						|
		chantyp := state.Chan.Type().Underlying().(*types.Chan)
 | 
						|
		elemtyp := fr.types.ToLLVM(chantyp.Elem())
 | 
						|
		if state.Dir == types.SendOnly {
 | 
						|
			ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "")
 | 
						|
			fr.builder.CreateStore(fr.llvmvalue(state.Send), ptrs[i])
 | 
						|
		} else {
 | 
						|
			// Only allocate stack space if the received value is used.
 | 
						|
			used := chanSelectStateUsed(sel, len(recvElems))
 | 
						|
			if used {
 | 
						|
				ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "")
 | 
						|
			} else {
 | 
						|
				ptrs[i] = llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0))
 | 
						|
			}
 | 
						|
			recvElems = append(recvElems, newValue(ptrs[i], chantyp.Elem()))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Create select{send,recv2} calls.
 | 
						|
	var receivedp llvm.Value
 | 
						|
	if len(recvElems) > 0 {
 | 
						|
		receivedp = fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(types.Typ[types.Bool]), "")
 | 
						|
	}
 | 
						|
	if !sel.Blocking {
 | 
						|
		// If the default case is chosen, the index must be -1.
 | 
						|
		fr.runtime.selectdefault.call(fr, selectp, llvm.ConstAllOnes(llvm.Int32Type()))
 | 
						|
	}
 | 
						|
	for i, state := range sel.States {
 | 
						|
		ch := fr.llvmvalue(state.Chan)
 | 
						|
		index := llvm.ConstInt(llvm.Int32Type(), uint64(i), false)
 | 
						|
		if state.Dir == types.SendOnly {
 | 
						|
			fr.runtime.selectsend.call(fr, selectp, ch, ptrs[i], index)
 | 
						|
		} else {
 | 
						|
			fr.runtime.selectrecv2.call(fr, selectp, ch, ptrs[i], receivedp, index)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Fire off the select.
 | 
						|
	index = newValue(fr.runtime.selectgo.call(fr, selectp)[0], types.Typ[types.Int])
 | 
						|
	if len(recvElems) > 0 {
 | 
						|
		recvOk = newValue(fr.builder.CreateLoad(receivedp, ""), types.Typ[types.Bool])
 | 
						|
		for _, recvElem := range recvElems {
 | 
						|
			recvElem.value = fr.builder.CreateLoad(recvElem.value, "")
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return index, recvOk, recvElems
 | 
						|
}
 | 
						|
 | 
						|
func chanSelectStateUsed(sel *ssa.Select, recvIndex int) bool {
 | 
						|
	for _, instr := range *sel.Referrers() {
 | 
						|
		extract, ok := instr.(*ssa.Extract)
 | 
						|
		if !ok || extract.Index != (recvIndex+2) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if len(*extract.Referrers()) > 0 {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 |