Esempio n. 1
0
File: types.go Progetto: minux/llgo
// tupleType returns a struct type with anonymous
// fields with the specified types.
func tupleType(fieldTypes ...types.Type) types.Type {
	vars := make([]*types.Var, len(fieldTypes))
	for i, t := range fieldTypes {
		vars[i] = types.NewParam(0, nil, fmt.Sprintf("f%d", i), t)
	}
	return types.NewStruct(vars, nil)
}
Esempio n. 2
0
// ResultList = Type | ParamList .
func (p *parser) parseResultList(pkg *types.Package) *types.Tuple {
	switch p.tok {
	case '<':
		return types.NewTuple(types.NewParam(token.NoPos, pkg, "", p.parseType(pkg)))

	case '(':
		params, _ := p.parseParamList(pkg)
		return params

	default:
		return nil
	}
}
Esempio n. 3
0
// Param = Name ["..."] Type .
func (p *parser) parseParam(pkg *types.Package) (param *types.Var, isVariadic bool) {
	name := p.parseName()
	if p.tok == '.' {
		p.next()
		p.expect('.')
		p.expect('.')
		isVariadic = true
	}
	typ := p.parseType(pkg)
	if isVariadic {
		typ = types.NewSlice(typ)
	}
	param = types.NewParam(token.NoPos, pkg, name, typ)
	return
}
Esempio n. 4
0
// newVar creates a 'var' for use in a types.Tuple.
func newVar(name string, typ types.Type) *types.Var {
	return types.NewParam(token.NoPos, nil, name, typ)
}
Esempio n. 5
0
File: ssa.go Progetto: pcc/llgo
// prepareCall returns the evaluated function and arguments.
//
// For builtins that may not be used in go/defer, prepareCall
// will emits inline code. In this case, prepareCall returns
// nil for fn and args, and returns a non-nil value for result.
func (fr *frame) prepareCall(instr ssa.CallInstruction) (fn *LLVMValue, args []*LLVMValue, result *LLVMValue) {
	call := instr.Common()
	args = make([]*LLVMValue, len(call.Args))
	for i, arg := range call.Args {
		args[i] = fr.value(arg)
	}

	if call.IsInvoke() {
		fn := fr.interfaceMethod(fr.value(call.Value), call.Method)
		return fn, args, nil
	}

	switch v := call.Value.(type) {
	case *ssa.Builtin:
		// handled below
	case *ssa.Function:
		// Function handled specially; value() will convert
		// a function to one with a context argument.
		fn = fr.resolveFunction(v)
		pair := llvm.ConstNull(fr.llvmtypes.ToLLVM(fn.Type()))
		pair = llvm.ConstInsertValue(pair, fn.LLVMValue(), []uint32{0})
		fn = fr.NewValue(pair, fn.Type())
		return fn, args, nil
	default:
		fn = fr.value(call.Value)
		return fn, args, nil
	}

	// Builtins may only be used in calls (i.e. can't be assigned),
	// and only print[ln], panic and recover may be used in go/defer.
	builtin := call.Value.(*ssa.Builtin)
	switch builtin.Name() {
	case "print", "println":
		// print/println generates a call-site specific anonymous
		// function to print the values. It's not inline because
		// print/println may be deferred.
		params := make([]*types.Var, len(call.Args))
		for i, arg := range call.Args {
			// make sure to use args[i].Type(), not call.Args[i].Type(),
			// as the evaluated expression converts untyped.
			params[i] = types.NewParam(arg.Pos(), nil, arg.Name(), args[i].Type())
		}
		sig := types.NewSignature(nil, nil, types.NewTuple(params...), nil, false)
		llfntyp := fr.llvmtypes.ToLLVM(sig)
		llfnptr := llvm.AddFunction(fr.module.Module, "", llfntyp.StructElementTypes()[0].ElementType())
		currBlock := fr.builder.GetInsertBlock()
		entry := llvm.AddBasicBlock(llfnptr, "entry")
		fr.builder.SetInsertPointAtEnd(entry)
		internalArgs := make([]Value, len(args))
		for i, arg := range args {
			internalArgs[i] = fr.NewValue(llfnptr.Param(i), arg.Type())
		}
		fr.printValues(builtin.Name() == "println", internalArgs...)
		fr.builder.CreateRetVoid()
		fr.builder.SetInsertPointAtEnd(currBlock)
		return fr.NewValue(llfnptr, sig), args, nil

	case "panic":
		panic("TODO: panic")

	case "recover":
		// TODO(axw) determine number of frames to skip in pc check
		indirect := fr.NewValue(llvm.ConstNull(llvm.Int32Type()), types.Typ[types.Int32])
		return fr.runtime.recover_, []*LLVMValue{indirect}, nil

	case "append":
		return nil, nil, fr.callAppend(args[0], args[1])

	case "close":
		return fr.runtime.chanclose, args, nil

	case "cap":
		return nil, nil, fr.callCap(args[0])

	case "len":
		return nil, nil, fr.callLen(args[0])

	case "copy":
		return nil, nil, fr.callCopy(args[0], args[1])

	case "delete":
		fr.callDelete(args[0], args[1])
		return nil, nil, nil

	case "real":
		return nil, nil, args[0].extractComplexComponent(0)

	case "imag":
		return nil, nil, args[0].extractComplexComponent(1)

	case "complex":
		r := args[0].LLVMValue()
		i := args[1].LLVMValue()
		typ := instr.Value().Type()
		cmplx := llvm.Undef(fr.llvmtypes.ToLLVM(typ))
		cmplx = fr.builder.CreateInsertValue(cmplx, r, 0, "")
		cmplx = fr.builder.CreateInsertValue(cmplx, i, 1, "")
		return nil, nil, fr.NewValue(cmplx, typ)

	default:
		panic("unimplemented: " + builtin.Name())
	}
}
Esempio n. 6
0
func (c *compiler) VisitFuncLit(lit *ast.FuncLit) Value {
	ftyp := c.typeinfo.Types[lit].(*types.Signature)

	// Walk the function literal, promoting stack vars not defined
	// in the function literal, and storing the ident's for non-const
	// values not declared in the function literal.
	//
	// (First, set a dummy "stack" value for the params and results.)
	var dummyfunc LLVMValue
	dummyfunc.stack = &dummyfunc
	paramVars := ftyp.Params()
	resultVars := ftyp.Results()
	c.functions.push(&function{
		LLVMValue: &dummyfunc,
		results:   resultVars,
	})
	v := &identVisitor{compiler: c}
	ast.Walk(v, lit.Body)
	c.functions.pop()

	// Create closure by adding a context parameter to the function,
	// and bind it with the values of the stack vars found in the
	// step above.
	origfnpairtyp := c.types.ToLLVM(ftyp)
	fnpairtyp := origfnpairtyp
	fntyp := origfnpairtyp.StructElementTypes()[0].ElementType()
	if v.captures != nil {
		// Add the additional context param.
		ctxfields := make([]*types.Var, len(v.captures))
		for i, capturevar := range v.captures {
			p := capturevar.Pkg()
			n := capturevar.Name()
			t := types.NewPointer(capturevar.Type())
			ctxfields[i] = types.NewParam(token.NoPos, p, n, t)
		}
		ctxtyp := types.NewPointer(types.NewStruct(ctxfields, nil))
		llvmctxtyp := c.types.ToLLVM(ctxtyp)
		rettyp := fntyp.ReturnType()
		paramtyps := append([]llvm.Type{llvmctxtyp}, fntyp.ParamTypes()...)
		vararg := fntyp.IsFunctionVarArg()
		fntyp = llvm.FunctionType(rettyp, paramtyps, vararg)
		opaqueptrtyp := origfnpairtyp.StructElementTypes()[1]
		elttyps := []llvm.Type{llvm.PointerType(fntyp, 0), opaqueptrtyp}
		fnpairtyp = llvm.StructType(elttyps, false)
	}

	fnptr := llvm.AddFunction(c.module.Module, "", fntyp)
	fnvalue := llvm.ConstNull(fnpairtyp)
	fnvalue = llvm.ConstInsertValue(fnvalue, fnptr, []uint32{0})
	currBlock := c.builder.GetInsertBlock()

	f := c.NewValue(fnvalue, ftyp)
	captureVars := types.NewTuple(v.captures...)
	c.buildFunction(f, captureVars, paramVars, resultVars, lit.Body)

	// Closure? Bind values to a context block.
	if v.captures != nil {
		// Store the free variables in the heap allocated block.
		block := c.createTypeMalloc(fntyp.ParamTypes()[0].ElementType())
		for i, contextvar := range v.captures {
			value := c.objectdata[contextvar].Value
			blockPtr := c.builder.CreateStructGEP(block, i, "")
			c.builder.CreateStore(value.pointer.LLVMValue(), blockPtr)
		}

		// Cast the function pointer type back to the original
		// type, without the context parameter.
		fnptr = llvm.ConstBitCast(fnptr, origfnpairtyp.StructElementTypes()[0])
		fnvalue = llvm.Undef(origfnpairtyp)
		fnvalue = llvm.ConstInsertValue(fnvalue, fnptr, []uint32{0})

		// Set the context value.
		i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
		block = c.builder.CreateBitCast(block, i8ptr, "")
		fnvalue = c.builder.CreateInsertValue(fnvalue, block, 1, "")
		f.value = fnvalue
	} else {
		c.builder.SetInsertPointAtEnd(currBlock)
	}

	return f
}