@@ -136,7 +136,7 @@ func (c *Compiler) emitSelect(frame *Frame, expr *ssa.Select) llvm.Value {
 	recvbuf := llvm.Undef(c.i8ptrType)
 	if hasReceives {
 		allocaType := llvm.ArrayType(c.ctx.Int8Type(), int(recvbufSize))
-		recvbufAlloca := c.builder.CreateAlloca(allocaType, "select.recvbuf.alloca")
+		recvbufAlloca, _, _ := c.createTemporaryAlloca(allocaType, "select.recvbuf.alloca")
 		recvbufAlloca.SetAlignment(recvbufAlign)
 		recvbuf = c.builder.CreateGEP(recvbufAlloca, []llvm.Value{
 			llvm.ConstInt(c.ctx.Int32Type(), 0, false),
package compiler

// This file lowers channel operations (make/send/recv/close) to runtime calls
// or pseudo-operations that are lowered during goroutine lowering.

import (
	"go/types"

	"golang.org/x/tools/go/ssa"
	"tinygo.org/x/go-llvm"
)

func (c *Compiler) emitMakeChan(frame *Frame, expr *ssa.MakeChan) llvm.Value {
	elementSize := c.targetData.TypeAllocSize(c.getLLVMType(expr.Type().(*types.Chan).Elem()))
	elementSizeValue := llvm.ConstInt(c.uintptrType, elementSize, false)
	bufSize := c.getValue(frame, expr.Size)
	return c.createRuntimeCall("chanMake", []llvm.Value{elementSizeValue, bufSize}, "")
}

// emitChanSend emits a pseudo chan send operation. It is lowered to the actual
// channel send operation during goroutine lowering.
func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) {
	ch := c.getValue(frame, instr.Chan)
	chanValue := c.getValue(frame, instr.X)

	// store value-to-send
	valueType := c.getLLVMType(instr.X.Type())
	valueAlloca, valueAllocaCast, valueAllocaSize := c.createTemporaryAlloca(valueType, "chan.value")
	c.builder.CreateStore(chanValue, valueAlloca)

	// Do the send.
	c.createRuntimeCall("chanSend", []llvm.Value{ch, valueAllocaCast}, "")

	// End the lifetime of the alloca.
	// This also works around a bug in CoroSplit, at least in LLVM 8:
	// https://bugs.llvm.org/show_bug.cgi?id=41742
	c.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
}

// emitChanRecv emits a pseudo chan receive operation. It is lowered to the
// actual channel receive operation during goroutine lowering.
func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) llvm.Value {
	valueType := c.getLLVMType(unop.X.Type().(*types.Chan).Elem())
	ch := c.getValue(frame, unop.X)

	// Allocate memory to receive into.
	valueAlloca, valueAllocaCast, valueAllocaSize := c.createTemporaryAlloca(valueType, "chan.value")

	// Do the receive.
	commaOk := c.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAllocaCast}, "")
	received := c.builder.CreateLoad(valueAlloca, "chan.received")
	c.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)

	if unop.CommaOk {
		tuple := llvm.Undef(c.ctx.StructType([]llvm.Type{valueType, c.ctx.Int1Type()}, false))
		tuple = c.builder.CreateInsertValue(tuple, received, 0, "")
		tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "")
		return tuple
	} else {
		return received
	}
}

// emitChanClose closes the given channel.
func (c *Compiler) emitChanClose(frame *Frame, param ssa.Value) {
	ch := c.getValue(frame, param)
	c.createRuntimeCall("chanClose", []llvm.Value{ch}, "")
}

// emitSelect emits all IR necessary for a select statements. That's a
// non-trivial amount of code because select is very complex to implement.
func (c *Compiler) emitSelect(frame *Frame, expr *ssa.Select) llvm.Value {
	if len(expr.States) == 0 {
		// Shortcuts for some simple selects.
		llvmType := c.getLLVMType(expr.Type())
		if expr.Blocking {
			// Blocks forever:
			//     select {}
			c.createRuntimeCall("deadlock", nil, "")
			return llvm.Undef(llvmType)
		} else {
			// No-op:
			//     select {
			//     default:
			//     }
			retval := llvm.Undef(llvmType)
			retval = c.builder.CreateInsertValue(retval, llvm.ConstInt(c.intType, 0xffffffffffffffff, true), 0, "")
			return retval // {-1, false}
		}
	}

	// This code create a (stack-allocated) slice containing all the select
	// cases and then calls runtime.chanSelect to perform the actual select
	// statement.
	// Simple selects (blocking and with just one case) are already transformed
	// into regular chan operations during SSA construction so we don't have to
	// optimize such small selects.

	// Go through all the cases. Create the selectStates slice and and
	// determine the receive buffer size and alignment.
	recvbufSize := uint64(0)
	recvbufAlign := 0
	hasReceives := false
	var selectStates []llvm.Value
	chanSelectStateType := c.getLLVMRuntimeType("chanSelectState")
	for _, state := range expr.States {
		ch := c.getValue(frame, state.Chan)
		selectState := llvm.ConstNull(chanSelectStateType)
		selectState = c.builder.CreateInsertValue(selectState, ch, 0, "")
		switch state.Dir {
		case types.RecvOnly:
			// Make sure the receive buffer is big enough and has the correct alignment.
			llvmType := c.getLLVMType(state.Chan.Type().(*types.Chan).Elem())
			if size := c.targetData.TypeAllocSize(llvmType); size > recvbufSize {
				recvbufSize = size
			}
			if align := c.targetData.ABITypeAlignment(llvmType); align > recvbufAlign {
				recvbufAlign = align
			}
			hasReceives = true
		case types.SendOnly:
			// Store this value in an alloca and put a pointer to this alloca
			// in the send state.
			sendValue := c.getValue(frame, state.Send)
			alloca := c.createEntryBlockAlloca(sendValue.Type(), "select.send.value")
			c.builder.CreateStore(sendValue, alloca)
			ptr := c.builder.CreateBitCast(alloca, c.i8ptrType, "")
			selectState = c.builder.CreateInsertValue(selectState, ptr, 1, "")
		default:
			panic("unreachable")
		}
		selectStates = append(selectStates, selectState)
	}

	// Create a receive buffer, where the received value will be stored.
	recvbuf := llvm.Undef(c.i8ptrType)
	if hasReceives {
		allocaType := llvm.ArrayType(c.ctx.Int8Type(), int(recvbufSize))
		recvbufAlloca := c.builder.CreateAlloca(allocaType, "select.recvbuf.alloca")
		recvbufAlloca.SetAlignment(recvbufAlign)
		recvbuf = c.builder.CreateGEP(recvbufAlloca, []llvm.Value{
			llvm.ConstInt(c.ctx.Int32Type(), 0, false),
			llvm.ConstInt(c.ctx.Int32Type(), 0, false),
		}, "select.recvbuf")
	}

	// Create the states slice (allocated on the stack).
	statesAllocaType := llvm.ArrayType(chanSelectStateType, len(selectStates))
	statesAlloca := c.builder.CreateAlloca(statesAllocaType, "select.states.alloca")
	for i, state := range selectStates {
		// Set each slice element to the appropriate channel.
		gep := c.builder.CreateGEP(statesAlloca, []llvm.Value{
			llvm.ConstInt(c.ctx.Int32Type(), 0, false),
			llvm.ConstInt(c.ctx.Int32Type(), uint64(i), false),
		}, "")
		c.builder.CreateStore(state, gep)
	}
	statesPtr := c.builder.CreateGEP(statesAlloca, []llvm.Value{
		llvm.ConstInt(c.ctx.Int32Type(), 0, false),
		llvm.ConstInt(c.ctx.Int32Type(), 0, false),
	}, "select.states")
	statesLen := llvm.ConstInt(c.uintptrType, uint64(len(selectStates)), false)

	// Convert the 'blocking' flag on this select into a LLVM value.
	blockingInt := uint64(0)
	if expr.Blocking {
		blockingInt = 1
	}
	blockingValue := llvm.ConstInt(c.ctx.Int1Type(), blockingInt, false)

	// Do the select in the runtime.
	results := c.createRuntimeCall("chanSelect", []llvm.Value{
		recvbuf,
		statesPtr, statesLen, statesLen, // []chanSelectState
		blockingValue,
	}, "")

	// The result value does not include all the possible received values,
	// because we can't load them in advance. Instead, the *ssa.Extract
	// instruction will treat a *ssa.Select specially and load it there inline.
	// Store the receive alloca in a sidetable until we hit this extract
	// instruction.
	if frame.selectRecvBuf == nil {
		frame.selectRecvBuf = make(map[*ssa.Select]llvm.Value)
	}
	frame.selectRecvBuf[expr] = recvbuf

	return results
}

// getChanSelectResult returns the special values from a *ssa.Extract expression
// when extracting a value from a select statement (*ssa.Select). Because
// *ssa.Select cannot load all values in advance, it does this later in the
// *ssa.Extract expression.
func (c *Compiler) getChanSelectResult(frame *Frame, expr *ssa.Extract) llvm.Value {
	if expr.Index == 0 {
		// index
		value := c.getValue(frame, expr.Tuple)
		index := c.builder.CreateExtractValue(value, expr.Index, "")
		if index.Type().IntTypeWidth() < c.intType.IntTypeWidth() {
			index = c.builder.CreateSExt(index, c.intType, "")
		}
		return index
	} else if expr.Index == 1 {
		// comma-ok
		value := c.getValue(frame, expr.Tuple)
		return c.builder.CreateExtractValue(value, expr.Index, "")
	} else {
		// Select statements are (index, ok, ...) where ... is a number of
		// received values, depending on how many receive statements there
		// are. They are all combined into one alloca (because only one
		// receive can proceed at a time) so we'll get that alloca, bitcast
		// it to the correct type, and dereference it.
		recvbuf := frame.selectRecvBuf[expr.Tuple.(*ssa.Select)]
		typ := llvm.PointerType(c.getLLVMType(expr.Type()), 0)
		ptr := c.builder.CreateBitCast(recvbuf, typ, "")
		return c.builder.CreateLoad(ptr, "")
	}
}

Ideally here as well. Unfortunately, this case is harder because the lifetime can only end after the value has been read back, that is, when a load has been created from `selectRecvBuf` (in `getChanSelectResult`).