Esempio n. 1
0
func (c *Codegen) stdString() {
	tmpl := &Template{
		Type:      llvm.GlobalContext().StructCreateNamed("string"),
		Variables: map[string]int{},
	}
	c.templates["string"] = tmpl

	vars := []llvm.Type{
		llvm.PointerType(PRIMITIVE_TYPES["char"], 0),
		PRIMITIVE_TYPES["int"],
		PRIMITIVE_TYPES["int"],
	}
	tmpl.Type.StructSetBody(vars, false)

	lenFuncType := llvm.FunctionType(PRIMITIVE_TYPES["int"], []llvm.Type{llvm.PointerType(tmpl.Type, 0)}, false)
	lenFunc := llvm.AddFunction(c.module, "-string-len", lenFuncType)
	lenFunc.Param(0).SetName("this")
	block := llvm.AddBasicBlock(c.module.NamedFunction("-string-len"), "entry")
	c.functions["-string-len"] = block
	c.currFunc = "-string-len"
	c.builder.SetInsertPoint(block, block.LastInstruction())
	ret := c.builder.CreateStructGEP(c.getCurrParam("this"), 1, "")
	ret = c.builder.CreateLoad(ret, "")
	ret = c.builder.CreateSub(ret, llvm.ConstInt(PRIMITIVE_TYPES["int"], 1, false), "")
	c.builder.CreateRet(ret)

	printFuncType := llvm.FunctionType(PRIMITIVE_TYPES["int"], []llvm.Type{
		llvm.PointerType(PRIMITIVE_TYPES["char"], 0),
	}, true)
	llvm.AddFunction(c.module, "printf", printFuncType)
}
Esempio n. 2
0
File: type.go Progetto: vnev/ark
func (v *Codegen) functionTypeToLLVMType(typ parser.FunctionType, ptr bool) llvm.Type {
	numOfParams := len(typ.Parameters)
	if typ.Receiver != nil {
		numOfParams++
	}

	params := make([]llvm.Type, 0, numOfParams)
	if typ.Receiver != nil {
		params = append(params, v.typeToLLVMType(typ.Receiver))
	}
	for _, par := range typ.Parameters {
		params = append(params, v.typeToLLVMType(par))
	}

	var returnType llvm.Type

	// oo theres a type, let's try figure it out
	if typ.Return != nil {
		returnType = v.typeToLLVMType(typ.Return)
	} else {
		returnType = llvm.VoidType()
	}

	// create the function type
	funcType := llvm.FunctionType(returnType, params, typ.IsVariadic)

	if ptr {
		funcType = llvm.PointerType(funcType, 0)
	}

	return funcType
}
Esempio n. 3
0
func (c *compiler) createInitMainFunction(mainPkg *ssa.Package) {
	int8ptr := llvm.PointerType(c.types.ctx.Int8Type(), 0)
	ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false)
	initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp)
	c.addCommonFunctionAttrs(initMain)
	entry := llvm.AddBasicBlock(initMain, "entry")

	builder := llvm.GlobalContext().NewBuilder()
	defer builder.Dispose()
	builder.SetInsertPointAtEnd(entry)

	args := []llvm.Value{llvm.Undef(int8ptr)}

	if !c.GccgoABI {
		initfn := c.module.Module.NamedFunction("main..import")
		if !initfn.IsNil() {
			builder.CreateCall(initfn, args, "")
		}
		builder.CreateRetVoid()
		return
	}

	initdata := c.buildPackageInitData(mainPkg)

	for _, init := range initdata.Inits {
		initfn := c.module.Module.NamedFunction(init.InitFunc)
		if initfn.IsNil() {
			initfn = llvm.AddFunction(c.module.Module, init.InitFunc, ftyp)
		}
		builder.CreateCall(initfn, args, "")
	}

	builder.CreateRetVoid()
}
Esempio n. 4
0
// emitInitPrologue emits the init-specific function prologue (guard check and
// initialization of dependent packages under the llgo native ABI), and returns
// the basic block into which the GC registration call should be emitted.
func (fr *frame) emitInitPrologue() llvm.BasicBlock {
	if fr.GccgoABI {
		return fr.builder.GetInsertBlock()
	}

	initGuard := llvm.AddGlobal(fr.module.Module, llvm.Int1Type(), "init$guard")
	initGuard.SetLinkage(llvm.InternalLinkage)
	initGuard.SetInitializer(llvm.ConstNull(llvm.Int1Type()))

	returnBlock := llvm.AddBasicBlock(fr.function, "")
	initBlock := llvm.AddBasicBlock(fr.function, "")

	initGuardVal := fr.builder.CreateLoad(initGuard, "")
	fr.builder.CreateCondBr(initGuardVal, returnBlock, initBlock)

	fr.builder.SetInsertPointAtEnd(returnBlock)
	fr.builder.CreateRetVoid()

	fr.builder.SetInsertPointAtEnd(initBlock)
	fr.builder.CreateStore(llvm.ConstInt(llvm.Int1Type(), 1, false), initGuard)
	int8ptr := llvm.PointerType(fr.types.ctx.Int8Type(), 0)
	ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false)
	for _, pkg := range fr.pkg.Object.Imports() {
		initname := ManglePackagePath(pkg.Path()) + "..import"
		initfn := fr.module.Module.NamedFunction(initname)
		if initfn.IsNil() {
			initfn = llvm.AddFunction(fr.module.Module, initname, ftyp)
		}
		args := []llvm.Value{llvm.Undef(int8ptr)}
		fr.builder.CreateCall(initfn, args, "")
	}

	return initBlock
}
Esempio n. 5
0
func (v *Codegen) declareFunctionDecl(n *parser.FunctionDecl) {
	mangledName := n.Function.MangledName(parser.MANGLE_ARK_UNSTABLE)
	function := v.curFile.Module.NamedFunction(mangledName)
	if !function.IsNil() {
		v.err("function `%s` already exists in module", n.Function.Name)
	} else {
		numOfParams := len(n.Function.Parameters)
		if n.Function.IsMethod && !n.Function.IsStatic {
			numOfParams++
		}

		params := make([]llvm.Type, 0, numOfParams)
		if n.Function.IsMethod && !n.Function.IsStatic {
			params = append(params, v.typeToLLVMType(n.Function.Receiver.Variable.Type))
		}
		for _, par := range n.Function.Parameters {
			params = append(params, v.typeToLLVMType(par.Variable.Type))
		}

		// attributes defaults
		cBinding := false

		// find them attributes yo
		if n.Function.Attrs != nil {
			cBinding = n.Function.Attrs.Contains("c")
		}

		// assume it's void
		funcTypeRaw := llvm.VoidType()

		// oo theres a type, let's try figure it out
		if n.Function.ReturnType != nil {
			funcTypeRaw = v.typeToLLVMType(n.Function.ReturnType)
		}

		// create the function type
		funcType := llvm.FunctionType(funcTypeRaw, params, n.Function.IsVariadic)

		functionName := mangledName
		if cBinding {
			functionName = n.Function.Name
		}

		// add that shit
		function = llvm.AddFunction(v.curFile.Module, functionName, funcType)

		/*// do some magical shit for later
		for i := 0; i < numOfParams; i++ {
			funcParam := function.Param(i)
			funcParam.SetName(n.Function.Parameters[i].Variable.MangledName(parser.MANGLE_ARK_UNSTABLE))
		}*/

		if cBinding {
			function.SetFunctionCallConv(llvm.CCallConv)
		} else {
			function.SetFunctionCallConv(llvm.FastCallConv)
		}
	}
}
Esempio n. 6
0
func (c *Codegen) declareMemcpy() {
	t := llvm.FunctionType(llvm.VoidType(), []llvm.Type{
		llvm.PointerType(PRIMITIVE_TYPES["char"], 0),
		llvm.PointerType(PRIMITIVE_TYPES["char"], 0),
		PRIMITIVE_TYPES["int"],
		PRIMITIVE_TYPES["int"],
		PRIMITIVE_TYPES["boolean"],
	}, false)
	llvm.AddFunction(c.module, "llvm.memcpy.p0i8.p0i8.i32", t)
}
Esempio n. 7
0
File: codegen.go Progetto: vnev/ark
func (v *Codegen) genRaiseSegfault() {
	fn := v.curFile.LlvmModule.NamedFunction("raise")
	intType := v.typeToLLVMType(parser.PRIMITIVE_int)

	if fn.IsNil() {
		fnType := llvm.FunctionType(intType, []llvm.Type{intType}, false)
		fn = llvm.AddFunction(v.curFile.LlvmModule, "raise", fnType)
	}

	v.builder().CreateCall(fn, []llvm.Value{llvm.ConstInt(intType, 11, false)}, "segfault")
}
Esempio n. 8
0
func (c *Codegen) getLLVMFuncType(ret parser.Node, params []*parser.VarDeclNode, obj llvm.Type) llvm.Type {
	p := make([]llvm.Type, 0)
	if obj != llvm.VoidType() {
		p = append(p, obj)
	}

	for _, v := range params {
		p = append(p, c.getLLVMType(v.Type))
	}

	return llvm.FunctionType(c.getLLVMType(ret), p, false)
}
Esempio n. 9
0
func (n *ProtoDecl) Gen(cg *CG) llvm.Value {
	var args []llvm.Type
	for _ = range n.Args {
		args = append(args, llvm.DoubleType())
	}
	typ := llvm.FunctionType(llvm.DoubleType(), args, false)
	fun := llvm.AddFunction(cg.Mod, n.Name, typ)

	if fun.BasicBlocksCount() != 0 {
		return errv("redefinition of function: " + n.Name)
	}

	if fun.ParamsCount() != len(n.Args) {
		return errv("redefinition of function with different number of args")
	}

	for i, param := range fun.Params() {
		param.SetName(n.Args[i])
	}

	return fun
}
Esempio n. 10
0
File: ssa.go Progetto: hinike/llgo
// bridgeRecoverFunc creates a function that may call recover(), and creates
// a call to it from the current frame. The created function will be called
// with a boolean parameter that indicates whether it may call recover().
//
// The created function will have the same name as the current frame's function
// with "$recover" appended, having the same return types and parameters with
// an additional boolean parameter appended.
//
// A new frame will be returned for the newly created function.
func (fr *frame) bridgeRecoverFunc(llfn llvm.Value, fti functionTypeInfo) *frame {
	// The bridging function must not be inlined, or the return address
	// may not correspond to the source function.
	llfn.AddFunctionAttr(llvm.NoInlineAttribute)

	// Call __go_can_recover, passing in the function's return address.
	entry := llvm.AddBasicBlock(llfn, "entry")
	fr.builder.SetInsertPointAtEnd(entry)
	canRecover := fr.runtime.canRecover.call(fr, fr.returnAddress(0))[0]
	returnType := fti.functionType.ReturnType()
	argTypes := fti.functionType.ParamTypes()
	argTypes = append(argTypes, canRecover.Type())

	// Create and call the $recover function.
	ftiRecover := fti
	ftiRecover.functionType = llvm.FunctionType(returnType, argTypes, false)
	llfnRecover := ftiRecover.declare(fr.module.Module, llfn.Name()+"$recover")
	fr.addCommonFunctionAttrs(llfnRecover)
	llfnRecover.SetLinkage(llvm.InternalLinkage)
	args := make([]llvm.Value, len(argTypes)-1, len(argTypes))
	for i := range args {
		args[i] = llfn.Param(i)
	}
	args = append(args, canRecover)
	result := fr.builder.CreateCall(llfnRecover, args, "")
	if returnType.TypeKind() == llvm.VoidTypeKind {
		fr.builder.CreateRetVoid()
	} else {
		fr.builder.CreateRet(result)
	}

	// The $recover function must condition calls to __go_recover on
	// the result of __go_can_recover passed in as an argument.
	fr = newFrame(fr.unit, llfnRecover)
	fr.retInf = ftiRecover.retInf
	fr.canRecover = fr.function.Param(len(argTypes) - 1)
	return fr
}
Esempio n. 11
0
func (c *compiler) createInitMainFunction(mainPkg *ssa.Package, initmap map[*types.Package]gccgoimporter.InitData) error {
	initdata := c.buildPackageInitData(mainPkg, initmap)

	ftyp := llvm.FunctionType(llvm.VoidType(), nil, false)
	initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp)
	c.addCommonFunctionAttrs(initMain)
	entry := llvm.AddBasicBlock(initMain, "entry")

	builder := llvm.GlobalContext().NewBuilder()
	defer builder.Dispose()
	builder.SetInsertPointAtEnd(entry)

	for _, init := range initdata.Inits {
		initfn := c.module.Module.NamedFunction(init.InitFunc)
		if initfn.IsNil() {
			initfn = llvm.AddFunction(c.module.Module, init.InitFunc, ftyp)
		}
		builder.CreateCall(initfn, nil, "")
	}

	builder.CreateRetVoid()
	return nil
}
Esempio n. 12
0
File: cabi.go Progetto: hinike/llgo
func (tm *llvmTypeMap) getFunctionTypeInfo(args []types.Type, results []types.Type) (fi functionTypeInfo) {
	var returnType llvm.Type
	var argTypes []llvm.Type
	if len(results) == 0 {
		returnType = llvm.VoidType()
		fi.retInf = &directRetInfo{}
	} else {
		aik := tm.classify(results...)

		var resultsType llvm.Type
		if len(results) == 1 {
			resultsType = tm.ToLLVM(results[0])
		} else {
			elements := make([]llvm.Type, len(results))
			for i := range elements {
				elements[i] = tm.ToLLVM(results[i])
			}
			resultsType = tm.ctx.StructType(elements, false)
		}

		switch aik {
		case AIK_Direct:
			var retFields []backendType
			for _, t := range results {
				retFields = append(retFields, tm.getBackendType(t))
			}
			bt := &structBType{retFields}

			retTypes, retAttrs, _, _ := tm.expandType(nil, nil, bt)
			switch len(retTypes) {
			case 0: // e.g., empty struct
				returnType = llvm.VoidType()
			case 1:
				returnType = retTypes[0]
				fi.retAttr = retAttrs[0]
			case 2:
				returnType = llvm.StructType(retTypes, false)
			default:
				panic("unexpected expandType result")
			}
			fi.retInf = &directRetInfo{numResults: len(results), retTypes: retTypes, resultsType: resultsType}

		case AIK_Indirect:
			returnType = llvm.VoidType()
			argTypes = []llvm.Type{llvm.PointerType(resultsType, 0)}
			fi.argAttrs = []llvm.Attribute{llvm.StructRetAttribute}
			fi.retInf = &indirectRetInfo{numResults: len(results), resultsType: resultsType}
		}
	}

	// Keep track of the number of INTEGER/SSE class registers remaining.
	remainingInt := 6
	remainingSSE := 8

	for _, arg := range args {
		aik := tm.classify(arg)

		isDirect := aik == AIK_Direct
		if isDirect {
			bt := tm.getBackendType(arg)
			directArgTypes, directArgAttrs, numInt, numSSE := tm.expandType(argTypes, fi.argAttrs, bt)

			// Check if the argument can fit into the remaining registers, or if
			// it would just occupy one register (which pushes the whole argument
			// onto the stack anyway).
			if numInt <= remainingInt && numSSE <= remainingSSE || numInt+numSSE == 1 {
				remainingInt -= numInt
				remainingSSE -= numSSE
				argInfo := &directArgInfo{argOffset: len(argTypes), valType: bt.ToLLVM(tm.ctx)}
				fi.argInfos = append(fi.argInfos, argInfo)
				argTypes = directArgTypes
				fi.argAttrs = directArgAttrs
				argInfo.argTypes = argTypes[argInfo.argOffset:len(argTypes)]
			} else {
				// No remaining registers; pass on the stack.
				isDirect = false
			}
		}

		if !isDirect {
			fi.argInfos = append(fi.argInfos, &indirectArgInfo{len(argTypes)})
			argTypes = append(argTypes, llvm.PointerType(tm.ToLLVM(arg), 0))
			fi.argAttrs = append(fi.argAttrs, llvm.ByValAttribute)
		}
	}

	fi.functionType = llvm.FunctionType(returnType, argTypes, false)
	return
}
Esempio n. 13
0
func newRuntimeInterface(module llvm.Module, tm *llvmTypeMap) (*runtimeInterface, error) {
	var ri runtimeInterface

	Bool := types.Typ[types.Bool]
	Complex128 := types.Typ[types.Complex128]
	Float64 := types.Typ[types.Float64]
	Int32 := types.Typ[types.Int32]
	Int64 := types.Typ[types.Int64]
	Int := types.Typ[types.Int]
	Rune := types.Typ[types.Rune]
	String := types.Typ[types.String]
	Uintptr := types.Typ[types.Uintptr]
	UnsafePointer := types.Typ[types.UnsafePointer]

	EmptyInterface := types.NewInterface(nil, nil)
	IntSlice := types.NewSlice(types.Typ[types.Int])

	for _, rt := range [...]struct {
		name      string
		rfi       *runtimeFnInfo
		args, res []types.Type
		attrs     []llvm.Attribute
	}{
		{
			name: "__go_append",
			rfi:  &ri.append,
			args: []types.Type{IntSlice, UnsafePointer, Uintptr, Uintptr},
			res:  []types.Type{IntSlice},
		},
		{
			name: "__go_assert_interface",
			rfi:  &ri.assertInterface,
			args: []types.Type{UnsafePointer, UnsafePointer},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_can_recover",
			rfi:  &ri.canRecover,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Bool},
		},
		{
			name: "__go_chan_cap",
			rfi:  &ri.chanCap,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Int},
		},
		{
			name: "__go_chan_len",
			rfi:  &ri.chanLen,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Int},
		},
		{
			name: "runtime.chanrecv2",
			rfi:  &ri.chanrecv2,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
			res:  []types.Type{Bool},
		},
		{
			name: "__go_check_defer",
			rfi:  &ri.checkDefer,
			args: []types.Type{UnsafePointer},
		},
		{
			name: "__go_check_interface_type",
			rfi:  &ri.checkInterfaceType,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
		},
		{
			name: "__go_builtin_close",
			rfi:  &ri.builtinClose,
			args: []types.Type{UnsafePointer},
		},
		{
			name: "__go_convert_interface",
			rfi:  &ri.convertInterface,
			args: []types.Type{UnsafePointer, UnsafePointer},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_copy",
			rfi:  &ri.copy,
			args: []types.Type{UnsafePointer, UnsafePointer, Uintptr},
		},
		{
			name: "__go_defer",
			rfi:  &ri.Defer,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
		},
		{
			name: "__go_deferred_recover",
			rfi:  &ri.deferredRecover,
			res:  []types.Type{EmptyInterface},
		},
		{
			name: "__go_empty_interface_compare",
			rfi:  &ri.emptyInterfaceCompare,
			args: []types.Type{EmptyInterface, EmptyInterface},
			res:  []types.Type{Int},
		},
		{
			name: "__go_go",
			rfi:  &ri.Go,
			args: []types.Type{UnsafePointer, UnsafePointer},
		},
		{
			name: "runtime.ifaceE2I2",
			rfi:  &ri.ifaceE2I2,
			args: []types.Type{UnsafePointer, EmptyInterface},
			res:  []types.Type{EmptyInterface, Bool},
		},
		{
			name: "runtime.ifaceI2I2",
			rfi:  &ri.ifaceI2I2,
			args: []types.Type{UnsafePointer, EmptyInterface},
			res:  []types.Type{EmptyInterface, Bool},
		},
		{
			name: "__go_int_array_to_string",
			rfi:  &ri.intArrayToString,
			args: []types.Type{UnsafePointer, Int},
			res:  []types.Type{String},
		},
		{
			name: "__go_int_to_string",
			rfi:  &ri.intToString,
			args: []types.Type{Int},
			res:  []types.Type{String},
		},
		{
			name: "__go_interface_compare",
			rfi:  &ri.interfaceCompare,
			args: []types.Type{EmptyInterface, EmptyInterface},
			res:  []types.Type{Int},
		},
		{
			name: "__go_make_slice2",
			rfi:  &ri.makeSlice,
			args: []types.Type{UnsafePointer, Uintptr, Uintptr},
			res:  []types.Type{IntSlice},
		},
		{
			name: "runtime.mapdelete",
			rfi:  &ri.mapdelete,
			args: []types.Type{UnsafePointer, UnsafePointer},
		},
		{
			name: "runtime.mapiter2",
			rfi:  &ri.mapiter2,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
		},
		{
			name: "runtime.mapiterinit",
			rfi:  &ri.mapiterinit,
			args: []types.Type{UnsafePointer, UnsafePointer},
		},
		{
			name: "runtime.mapiternext",
			rfi:  &ri.mapiternext,
			args: []types.Type{UnsafePointer},
		},
		{
			name: "__go_map_index",
			rfi:  &ri.mapIndex,
			args: []types.Type{UnsafePointer, UnsafePointer, Bool},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_map_len",
			rfi:  &ri.mapLen,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Int},
		},
		{
			name: "__go_new",
			rfi:  &ri.New,
			args: []types.Type{UnsafePointer, Uintptr},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_new_channel",
			rfi:  &ri.newChannel,
			args: []types.Type{UnsafePointer, Uintptr},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_new_map",
			rfi:  &ri.newMap,
			args: []types.Type{UnsafePointer, Uintptr},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "__go_new_nopointers",
			rfi:  &ri.NewNopointers,
			args: []types.Type{UnsafePointer, Uintptr},
			res:  []types.Type{UnsafePointer},
		},
		{
			name: "runtime.newselect",
			rfi:  &ri.newSelect,
			args: []types.Type{Int32},
			res:  []types.Type{UnsafePointer},
		},
		{
			name:  "__go_panic",
			rfi:   &ri.panic,
			args:  []types.Type{EmptyInterface},
			attrs: []llvm.Attribute{llvm.NoReturnAttribute},
		},
		{
			name: "__go_print_bool",
			rfi:  &ri.printBool,
			args: []types.Type{Bool},
		},
		{
			name: "__go_print_complex",
			rfi:  &ri.printComplex,
			args: []types.Type{Complex128},
		},
		{
			name: "__go_print_double",
			rfi:  &ri.printDouble,
			args: []types.Type{Float64},
		},
		{
			name: "__go_print_empty_interface",
			rfi:  &ri.printEmptyInterface,
			args: []types.Type{EmptyInterface},
		},
		{
			name: "__go_print_interface",
			rfi:  &ri.printInterface,
			args: []types.Type{EmptyInterface},
		},
		{
			name: "__go_print_int64",
			rfi:  &ri.printInt64,
			args: []types.Type{Int64},
		},
		{
			name: "__go_print_nl",
			rfi:  &ri.printNl,
		},
		{
			name: "__go_print_pointer",
			rfi:  &ri.printPointer,
			args: []types.Type{UnsafePointer},
		},
		{
			name: "__go_print_slice",
			rfi:  &ri.printSlice,
			args: []types.Type{IntSlice},
		},
		{
			name: "__go_print_space",
			rfi:  &ri.printSpace,
		},
		{
			name: "__go_print_string",
			rfi:  &ri.printString,
			args: []types.Type{String},
		},
		{
			name: "__go_print_uint64",
			rfi:  &ri.printUint64,
			args: []types.Type{Int64},
		},
		{
			name: "__go_receive",
			rfi:  &ri.receive,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
		},
		{
			name: "__go_recover",
			rfi:  &ri.recover,
			res:  []types.Type{EmptyInterface},
		},
		{
			name: "__go_register_gc_roots",
			rfi:  &ri.registerGcRoots,
			args: []types.Type{UnsafePointer},
		},
		{
			name:  "__go_runtime_error",
			rfi:   &ri.runtimeError,
			args:  []types.Type{Int32},
			attrs: []llvm.Attribute{llvm.NoReturnAttribute},
		},
		{
			name: "runtime.selectdefault",
			rfi:  &ri.selectdefault,
			args: []types.Type{UnsafePointer, Int32},
		},
		{
			name: "runtime.selectgo",
			rfi:  &ri.selectgo,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Int},
		},
		{
			name: "runtime.selectrecv2",
			rfi:  &ri.selectrecv2,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, UnsafePointer, Int32},
		},
		{
			name: "runtime.selectsend",
			rfi:  &ri.selectsend,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, Int32},
		},
		{
			name: "__go_send_big",
			rfi:  &ri.sendBig,
			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
		},
		{
			name: "__go_set_defer_retaddr",
			rfi:  &ri.setDeferRetaddr,
			args: []types.Type{UnsafePointer},
			res:  []types.Type{Bool},
		},
		{
			name: "__go_strcmp",
			rfi:  &ri.strcmp,
			args: []types.Type{String, String},
			res:  []types.Type{Int},
		},
		{
			name: "__go_string_plus",
			rfi:  &ri.stringPlus,
			args: []types.Type{String, String},
			res:  []types.Type{String},
		},
		{
			name: "__go_string_slice",
			rfi:  &ri.stringSlice,
			args: []types.Type{String, Int, Int},
			res:  []types.Type{String},
		},
		{
			name: "__go_string_to_int_array",
			rfi:  &ri.stringToIntArray,
			args: []types.Type{String},
			res:  []types.Type{IntSlice},
		},
		{
			name: "runtime.stringiter2",
			rfi:  &ri.stringiter2,
			args: []types.Type{String, Int},
			res:  []types.Type{Int, Rune},
		},
		{
			name: "__go_type_descriptors_equal",
			rfi:  &ri.typeDescriptorsEqual,
			args: []types.Type{UnsafePointer, UnsafePointer},
			res:  []types.Type{Bool},
		},
		{
			name: "__go_undefer",
			rfi:  &ri.undefer,
			args: []types.Type{UnsafePointer},
		},
	} {
		rt.rfi.init(tm, module, rt.name, rt.args, rt.res)
		for _, attr := range rt.attrs {
			rt.rfi.fn.AddFunctionAttr(attr)
		}
	}

	memsetName := "llvm.memset.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth())
	memsetType := llvm.FunctionType(
		llvm.VoidType(),
		[]llvm.Type{
			llvm.PointerType(llvm.Int8Type(), 0),
			llvm.Int8Type(),
			tm.target.IntPtrType(),
			llvm.Int32Type(),
			llvm.Int1Type(),
		},
		false,
	)
	ri.memset = llvm.AddFunction(module, memsetName, memsetType)

	memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth())
	memcpyType := llvm.FunctionType(
		llvm.VoidType(),
		[]llvm.Type{
			llvm.PointerType(llvm.Int8Type(), 0),
			llvm.PointerType(llvm.Int8Type(), 0),
			tm.target.IntPtrType(),
			llvm.Int32Type(),
			llvm.Int1Type(),
		},
		false,
	)
	ri.memcpy = llvm.AddFunction(module, memcpyName, memcpyType)

	returnaddressType := llvm.FunctionType(
		llvm.PointerType(llvm.Int8Type(), 0),
		[]llvm.Type{llvm.Int32Type()},
		false,
	)
	ri.returnaddress = llvm.AddFunction(module, "llvm.returnaddress", returnaddressType)

	gccgoPersonalityType := llvm.FunctionType(
		llvm.Int32Type(),
		[]llvm.Type{
			llvm.Int32Type(),
			llvm.Int64Type(),
			llvm.PointerType(llvm.Int8Type(), 0),
			llvm.PointerType(llvm.Int8Type(), 0),
		},
		false,
	)
	ri.gccgoPersonality = llvm.AddFunction(module, "__gccgo_personality_v0", gccgoPersonalityType)

	ri.gccgoExceptionType = llvm.StructType(
		[]llvm.Type{
			llvm.PointerType(llvm.Int8Type(), 0),
			llvm.Int32Type(),
		},
		false,
	)

	return &ri, nil
}
Esempio n. 14
0
// createThunk creates a thunk from a
// given function and arguments, suitable for use with
// "defer" and "go".
func (fr *frame) createThunk(call ssa.CallInstruction) (thunk llvm.Value, arg llvm.Value) {
	seenarg := make(map[ssa.Value]bool)
	var args []ssa.Value
	var argtypes []*types.Var

	packArg := func(arg ssa.Value) {
		switch arg.(type) {
		case *ssa.Builtin, *ssa.Function, *ssa.Const, *ssa.Global:
			// Do nothing: we can generate these in the thunk
		default:
			if !seenarg[arg] {
				seenarg[arg] = true
				args = append(args, arg)
				field := types.NewField(0, nil, "_", arg.Type(), true)
				argtypes = append(argtypes, field)
			}
		}
	}

	packArg(call.Common().Value)
	for _, arg := range call.Common().Args {
		packArg(arg)
	}

	var isRecoverCall bool
	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	var structllptr llvm.Type
	if len(args) == 0 {
		if builtin, ok := call.Common().Value.(*ssa.Builtin); ok {
			isRecoverCall = builtin.Name() == "recover"
		}
		if isRecoverCall {
			// When creating a thunk for recover(), we must pass fr.canRecover.
			arg = fr.builder.CreateZExt(fr.canRecover, fr.target.IntPtrType(), "")
			arg = fr.builder.CreateIntToPtr(arg, i8ptr, "")
		} else {
			arg = llvm.ConstPointerNull(i8ptr)
		}
	} else {
		structtype := types.NewStruct(argtypes, nil)
		arg = fr.createTypeMalloc(structtype)
		structllptr = arg.Type()
		for i, ssaarg := range args {
			argptr := fr.builder.CreateStructGEP(arg, i, "")
			fr.builder.CreateStore(fr.llvmvalue(ssaarg), argptr)
		}
		arg = fr.builder.CreateBitCast(arg, i8ptr, "")
	}

	thunkfntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{i8ptr}, false)
	thunkfn := llvm.AddFunction(fr.module.Module, "", thunkfntype)
	thunkfn.SetLinkage(llvm.InternalLinkage)
	fr.addCommonFunctionAttrs(thunkfn)

	thunkfr := newFrame(fr.unit, thunkfn)
	defer thunkfr.dispose()

	prologuebb := llvm.AddBasicBlock(thunkfn, "prologue")
	thunkfr.builder.SetInsertPointAtEnd(prologuebb)

	if isRecoverCall {
		thunkarg := thunkfn.Param(0)
		thunkarg = thunkfr.builder.CreatePtrToInt(thunkarg, fr.target.IntPtrType(), "")
		thunkfr.canRecover = thunkfr.builder.CreateTrunc(thunkarg, llvm.Int1Type(), "")
	} else if len(args) > 0 {
		thunkarg := thunkfn.Param(0)
		thunkarg = thunkfr.builder.CreateBitCast(thunkarg, structllptr, "")
		for i, ssaarg := range args {
			thunkargptr := thunkfr.builder.CreateStructGEP(thunkarg, i, "")
			thunkarg := thunkfr.builder.CreateLoad(thunkargptr, "")
			thunkfr.env[ssaarg] = newValue(thunkarg, ssaarg.Type())
		}
	}

	_, isDefer := call.(*ssa.Defer)

	entrybb := llvm.AddBasicBlock(thunkfn, "entry")
	br := thunkfr.builder.CreateBr(entrybb)
	thunkfr.allocaBuilder.SetInsertPointBefore(br)

	thunkfr.builder.SetInsertPointAtEnd(entrybb)
	var exitbb llvm.BasicBlock
	if isDefer {
		exitbb = llvm.AddBasicBlock(thunkfn, "exit")
		thunkfr.runtime.setDeferRetaddr.call(thunkfr, llvm.BlockAddress(thunkfn, exitbb))
	}
	if isDefer && isRecoverCall {
		thunkfr.callRecover(true)
	} else {
		thunkfr.callInstruction(call)
	}
	if isDefer {
		thunkfr.builder.CreateBr(exitbb)
		thunkfr.builder.SetInsertPointAtEnd(exitbb)
	}
	thunkfr.builder.CreateRetVoid()

	thunk = fr.builder.CreateBitCast(thunkfn, i8ptr, "")
	return
}
Esempio n. 15
0
func (v *Codegen) declareFunctionDecl(n *parser.FunctionDecl) {
	mangledName := n.Function.MangledName(parser.MANGLE_ARK_UNSTABLE)
	function := v.curFile.Module.NamedFunction(mangledName)
	if !function.IsNil() {
		v.err("function `%s` already exists in module", n.Function.Name)
	} else {
		numOfParams := len(n.Function.Parameters)
		params := make([]llvm.Type, numOfParams)
		for i, par := range n.Function.Parameters {
			params[i] = v.typeToLLVMType(par.Variable.Type)
		}

		// attributes defaults
		cBinding := false

		// find them attributes yo
		if n.Function.Attrs != nil {
			attributes := n.Function.Attrs

			// todo hashmap or some shit
			for _, attr := range attributes {
				switch attr.Key {
				case "c":
					cBinding = true
				default:
					// do nothing
				}
			}
		}

		// assume it's void
		funcTypeRaw := llvm.VoidType()

		// oo theres a type, let's try figure it out
		if n.Function.ReturnType != nil {
			funcTypeRaw = v.typeToLLVMType(n.Function.ReturnType)
		}

		// create the function type
		funcType := llvm.FunctionType(funcTypeRaw, params, n.Function.IsVariadic)

		functionName := mangledName
		if cBinding {
			functionName = n.Function.Name
		}

		// add that shit
		function = llvm.AddFunction(v.curFile.Module, functionName, funcType)

		// do some magical shit for later
		for i := 0; i < numOfParams; i++ {
			funcParam := function.Param(i)
			funcParam.SetName(n.Function.Parameters[i].Variable.MangledName(parser.MANGLE_ARK_UNSTABLE))
		}

		if cBinding {
			function.SetFunctionCallConv(llvm.CCallConv)
		} else {
			function.SetFunctionCallConv(llvm.FastCallConv)
		}
	}
}
Esempio n. 16
0
func (v *Codegen) genVariableDecl(n *parser.VariableDecl, semicolon bool) llvm.Value {
	var res llvm.Value

	if v.inFunction {
		mangledName := n.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE)

		funcEntry := v.currentFunction.EntryBasicBlock()

		// use this builder for the variable alloca
		// this means all allocas go at the start of the function
		// so each variable is only allocated once
		allocBuilder := llvm.NewBuilder()

		if funcEntry == v.builder.GetInsertBlock() {
			allocBuilder.SetInsertPointAtEnd(funcEntry)
		} else {
			allocBuilder.SetInsertPointBefore(funcEntry.LastInstruction())
		}

		alloc := allocBuilder.CreateAlloca(v.typeToLLVMType(n.Variable.Type), mangledName)

		// set allocated memory to zero
		fn := v.curFile.Module.NamedFunction("llvm.memset.p0i8.i32")
		if fn.IsNil() {
			fnType := llvm.FunctionType(llvm.VoidType(), []llvm.Type{llvm.PointerType(llvm.IntType(8), 0), llvm.IntType(8), llvm.IntType(32), llvm.IntType(32), llvm.IntType(1)}, false)
			fn = llvm.AddFunction(v.curFile.Module, "llvm.memset.p0i8.i32", fnType)
		}

		// cast alloc to byte array
		castAlloc := allocBuilder.CreateBitCast(alloc, llvm.PointerType(llvm.IntType(8), 0), "")

		// get type length
		gep := allocBuilder.CreateGEP(llvm.ConstNull(llvm.PointerType(v.typeToLLVMType(n.Variable.Type), 0)), []llvm.Value{llvm.ConstInt(llvm.IntType(32), 1, false)}, "")
		length := allocBuilder.CreatePtrToInt(gep, llvm.IntType(32), "")

		// call memset intrinsic
		allocBuilder.CreateCall(fn, []llvm.Value{castAlloc, llvm.ConstInt(llvm.IntType(8), 0, false), length, llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(1), 0, false)}, "")

		allocBuilder.Dispose()

		v.variableLookup[n.Variable] = alloc

		if n.Assignment != nil {
			if value := v.genExpr(n.Assignment); !value.IsNil() {
				v.builder.CreateStore(value, alloc)
			}
		}
	} else {
		mangledName := n.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE)
		varType := v.typeToLLVMType(n.Variable.Type)
		value := llvm.AddGlobal(v.curFile.Module, varType, mangledName)
		value.SetLinkage(llvm.InternalLinkage)
		value.SetGlobalConstant(!n.Variable.Mutable)
		if n.Assignment != nil {
			value.SetInitializer(v.genExpr(n.Assignment))
		}
		v.variableLookup[n.Variable] = value
	}

	return res
}