github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/irgen/runtime.go (about)

     1  //===- runtime.go - IR generation for runtime calls -----------------------===//
     2  //
     3  //                     The LLVM Compiler Infrastructure
     4  //
     5  // This file is distributed under the University of Illinois Open Source
     6  // License. See LICENSE.TXT for details.
     7  //
     8  //===----------------------------------------------------------------------===//
     9  //
    10  // This file implements IR generation for calls to the runtime library.
    11  //
    12  //===----------------------------------------------------------------------===//
    13  
    14  package irgen
    15  
    16  import (
    17  	"strconv"
    18  
    19  	"llvm.org/llgo/third_party/gotools/go/types"
    20  
    21  	"llvm.org/llvm/bindings/go/llvm"
    22  )
    23  
    24  type runtimeFnInfo struct {
    25  	fi *functionTypeInfo
    26  	fn llvm.Value
    27  }
    28  
    29  func (rfi *runtimeFnInfo) init(tm *llvmTypeMap, m llvm.Module, name string, args []types.Type, results []types.Type) {
    30  	rfi.fi = new(functionTypeInfo)
    31  	*rfi.fi = tm.getFunctionTypeInfo(args, results)
    32  	rfi.fn = rfi.fi.declare(m, name)
    33  }
    34  
    35  func (rfi *runtimeFnInfo) call(f *frame, args ...llvm.Value) []llvm.Value {
    36  	if f.unwindBlock.IsNil() {
    37  		return rfi.callOnly(f, args...)
    38  	} else {
    39  		return rfi.invoke(f, f.unwindBlock, args...)
    40  	}
    41  }
    42  
    43  func (rfi *runtimeFnInfo) callOnly(f *frame, args ...llvm.Value) []llvm.Value {
    44  	return rfi.fi.call(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, llvm.Value{nil}, args)
    45  }
    46  
    47  func (rfi *runtimeFnInfo) invoke(f *frame, lpad llvm.BasicBlock, args ...llvm.Value) []llvm.Value {
    48  	contbb := llvm.AddBasicBlock(f.function, "")
    49  	return rfi.fi.invoke(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, llvm.Value{nil}, args, contbb, lpad)
    50  }
    51  
    52  // runtimeInterface is a struct containing references to
    53  // runtime types and intrinsic function declarations.
    54  type runtimeInterface struct {
    55  	// LLVM intrinsics
    56  	memcpy,
    57  	memset,
    58  	returnaddress llvm.Value
    59  
    60  	// Exception handling support
    61  	gccgoPersonality   llvm.Value
    62  	gccgoExceptionType llvm.Type
    63  
    64  	// Runtime intrinsics
    65  	append,
    66  	assertInterface,
    67  	byteArrayToString,
    68  	canRecover,
    69  	chanCap,
    70  	chanLen,
    71  	chanrecv2,
    72  	checkDefer,
    73  	checkInterfaceType,
    74  	builtinClose,
    75  	convertInterface,
    76  	copy,
    77  	Defer,
    78  	deferredRecover,
    79  	emptyInterfaceCompare,
    80  	Go,
    81  	ifaceE2I2,
    82  	ifaceI2I2,
    83  	intArrayToString,
    84  	interfaceCompare,
    85  	intToString,
    86  	makeSlice,
    87  	mapdelete,
    88  	mapiter2,
    89  	mapiterinit,
    90  	mapiternext,
    91  	mapIndex,
    92  	mapLen,
    93  	New,
    94  	newChannel,
    95  	newMap,
    96  	newSelect,
    97  	panic,
    98  	printBool,
    99  	printComplex,
   100  	printDouble,
   101  	printEmptyInterface,
   102  	printInterface,
   103  	printInt64,
   104  	printNl,
   105  	printPointer,
   106  	printSlice,
   107  	printSpace,
   108  	printString,
   109  	printUint64,
   110  	receive,
   111  	recover,
   112  	registerGcRoots,
   113  	runtimeError,
   114  	selectdefault,
   115  	selectrecv2,
   116  	selectsend,
   117  	selectgo,
   118  	sendBig,
   119  	setDeferRetaddr,
   120  	strcmp,
   121  	stringiter2,
   122  	stringPlus,
   123  	stringSlice,
   124  	stringToByteArray,
   125  	stringToIntArray,
   126  	typeDescriptorsEqual,
   127  	undefer runtimeFnInfo
   128  }
   129  
   130  func newRuntimeInterface(module llvm.Module, tm *llvmTypeMap) (*runtimeInterface, error) {
   131  	var ri runtimeInterface
   132  
   133  	Bool := types.Typ[types.Bool]
   134  	Complex128 := types.Typ[types.Complex128]
   135  	Float64 := types.Typ[types.Float64]
   136  	Int32 := types.Typ[types.Int32]
   137  	Int64 := types.Typ[types.Int64]
   138  	Int := types.Typ[types.Int]
   139  	Rune := types.Typ[types.Rune]
   140  	String := types.Typ[types.String]
   141  	Uintptr := types.Typ[types.Uintptr]
   142  	UnsafePointer := types.Typ[types.UnsafePointer]
   143  
   144  	EmptyInterface := types.NewInterface(nil, nil)
   145  	ByteSlice := types.NewSlice(types.Typ[types.Byte])
   146  	IntSlice := types.NewSlice(types.Typ[types.Int])
   147  
   148  	for _, rt := range [...]struct {
   149  		name      string
   150  		rfi       *runtimeFnInfo
   151  		args, res []types.Type
   152  		attrs     []llvm.Attribute
   153  	}{
   154  		{
   155  			name: "__go_append",
   156  			rfi:  &ri.append,
   157  			args: []types.Type{IntSlice, UnsafePointer, Uintptr, Uintptr},
   158  			res:  []types.Type{IntSlice},
   159  		},
   160  		{
   161  			name: "__go_assert_interface",
   162  			rfi:  &ri.assertInterface,
   163  			args: []types.Type{UnsafePointer, UnsafePointer},
   164  			res:  []types.Type{UnsafePointer},
   165  		},
   166  		{
   167  			name:  "__go_byte_array_to_string",
   168  			rfi:   &ri.byteArrayToString,
   169  			args:  []types.Type{UnsafePointer, Int},
   170  			res:   []types.Type{String},
   171  			attrs: []llvm.Attribute{llvm.NoUnwindAttribute},
   172  		},
   173  		{
   174  			name: "__go_can_recover",
   175  			rfi:  &ri.canRecover,
   176  			args: []types.Type{UnsafePointer},
   177  			res:  []types.Type{Bool},
   178  		},
   179  		{
   180  			name: "__go_chan_cap",
   181  			rfi:  &ri.chanCap,
   182  			args: []types.Type{UnsafePointer},
   183  			res:  []types.Type{Int},
   184  		},
   185  		{
   186  			name: "__go_chan_len",
   187  			rfi:  &ri.chanLen,
   188  			args: []types.Type{UnsafePointer},
   189  			res:  []types.Type{Int},
   190  		},
   191  		{
   192  			name: "runtime.chanrecv2",
   193  			rfi:  &ri.chanrecv2,
   194  			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
   195  			res:  []types.Type{Bool},
   196  		},
   197  		{
   198  			name: "__go_check_defer",
   199  			rfi:  &ri.checkDefer,
   200  			args: []types.Type{UnsafePointer},
   201  		},
   202  		{
   203  			name: "__go_check_interface_type",
   204  			rfi:  &ri.checkInterfaceType,
   205  			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
   206  		},
   207  		{
   208  			name: "__go_builtin_close",
   209  			rfi:  &ri.builtinClose,
   210  			args: []types.Type{UnsafePointer},
   211  		},
   212  		{
   213  			name: "__go_convert_interface",
   214  			rfi:  &ri.convertInterface,
   215  			args: []types.Type{UnsafePointer, UnsafePointer},
   216  			res:  []types.Type{UnsafePointer},
   217  		},
   218  		{
   219  			name: "__go_copy",
   220  			rfi:  &ri.copy,
   221  			args: []types.Type{UnsafePointer, UnsafePointer, Uintptr},
   222  		},
   223  		{
   224  			name: "__go_defer",
   225  			rfi:  &ri.Defer,
   226  			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
   227  		},
   228  		{
   229  			name: "__go_deferred_recover",
   230  			rfi:  &ri.deferredRecover,
   231  			res:  []types.Type{EmptyInterface},
   232  		},
   233  		{
   234  			name: "__go_empty_interface_compare",
   235  			rfi:  &ri.emptyInterfaceCompare,
   236  			args: []types.Type{EmptyInterface, EmptyInterface},
   237  			res:  []types.Type{Int},
   238  		},
   239  		{
   240  			name: "__go_go",
   241  			rfi:  &ri.Go,
   242  			args: []types.Type{UnsafePointer, UnsafePointer},
   243  		},
   244  		{
   245  			name: "runtime.ifaceE2I2",
   246  			rfi:  &ri.ifaceE2I2,
   247  			args: []types.Type{UnsafePointer, EmptyInterface},
   248  			res:  []types.Type{EmptyInterface, Bool},
   249  		},
   250  		{
   251  			name: "runtime.ifaceI2I2",
   252  			rfi:  &ri.ifaceI2I2,
   253  			args: []types.Type{UnsafePointer, EmptyInterface},
   254  			res:  []types.Type{EmptyInterface, Bool},
   255  		},
   256  		{
   257  			name: "__go_int_array_to_string",
   258  			rfi:  &ri.intArrayToString,
   259  			args: []types.Type{UnsafePointer, Int},
   260  			res:  []types.Type{String},
   261  		},
   262  		{
   263  			name: "__go_int_to_string",
   264  			rfi:  &ri.intToString,
   265  			args: []types.Type{Int},
   266  			res:  []types.Type{String},
   267  		},
   268  		{
   269  			name: "__go_interface_compare",
   270  			rfi:  &ri.interfaceCompare,
   271  			args: []types.Type{EmptyInterface, EmptyInterface},
   272  			res:  []types.Type{Int},
   273  		},
   274  		{
   275  			name: "__go_make_slice2",
   276  			rfi:  &ri.makeSlice,
   277  			args: []types.Type{UnsafePointer, Uintptr, Uintptr},
   278  			res:  []types.Type{IntSlice},
   279  		},
   280  		{
   281  			name: "runtime.mapdelete",
   282  			rfi:  &ri.mapdelete,
   283  			args: []types.Type{UnsafePointer, UnsafePointer},
   284  		},
   285  		{
   286  			name: "runtime.mapiter2",
   287  			rfi:  &ri.mapiter2,
   288  			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
   289  		},
   290  		{
   291  			name: "runtime.mapiterinit",
   292  			rfi:  &ri.mapiterinit,
   293  			args: []types.Type{UnsafePointer, UnsafePointer},
   294  		},
   295  		{
   296  			name: "runtime.mapiternext",
   297  			rfi:  &ri.mapiternext,
   298  			args: []types.Type{UnsafePointer},
   299  		},
   300  		{
   301  			name: "__go_map_index",
   302  			rfi:  &ri.mapIndex,
   303  			args: []types.Type{UnsafePointer, UnsafePointer, Bool},
   304  			res:  []types.Type{UnsafePointer},
   305  		},
   306  		{
   307  			name: "__go_map_len",
   308  			rfi:  &ri.mapLen,
   309  			args: []types.Type{UnsafePointer},
   310  			res:  []types.Type{Int},
   311  		},
   312  		{
   313  			name:  "__go_new",
   314  			rfi:   &ri.New,
   315  			args:  []types.Type{UnsafePointer, Uintptr},
   316  			res:   []types.Type{UnsafePointer},
   317  			attrs: []llvm.Attribute{llvm.NoUnwindAttribute},
   318  		},
   319  		{
   320  			name: "__go_new_channel",
   321  			rfi:  &ri.newChannel,
   322  			args: []types.Type{UnsafePointer, Uintptr},
   323  			res:  []types.Type{UnsafePointer},
   324  		},
   325  		{
   326  			name: "__go_new_map",
   327  			rfi:  &ri.newMap,
   328  			args: []types.Type{UnsafePointer, Uintptr},
   329  			res:  []types.Type{UnsafePointer},
   330  		},
   331  		{
   332  			name: "runtime.newselect",
   333  			rfi:  &ri.newSelect,
   334  			args: []types.Type{Int32},
   335  			res:  []types.Type{UnsafePointer},
   336  		},
   337  		{
   338  			name:  "__go_panic",
   339  			rfi:   &ri.panic,
   340  			args:  []types.Type{EmptyInterface},
   341  			attrs: []llvm.Attribute{llvm.NoReturnAttribute},
   342  		},
   343  		{
   344  			name: "__go_print_bool",
   345  			rfi:  &ri.printBool,
   346  			args: []types.Type{Bool},
   347  		},
   348  		{
   349  			name: "__go_print_complex",
   350  			rfi:  &ri.printComplex,
   351  			args: []types.Type{Complex128},
   352  		},
   353  		{
   354  			name: "__go_print_double",
   355  			rfi:  &ri.printDouble,
   356  			args: []types.Type{Float64},
   357  		},
   358  		{
   359  			name: "__go_print_empty_interface",
   360  			rfi:  &ri.printEmptyInterface,
   361  			args: []types.Type{EmptyInterface},
   362  		},
   363  		{
   364  			name: "__go_print_interface",
   365  			rfi:  &ri.printInterface,
   366  			args: []types.Type{EmptyInterface},
   367  		},
   368  		{
   369  			name: "__go_print_int64",
   370  			rfi:  &ri.printInt64,
   371  			args: []types.Type{Int64},
   372  		},
   373  		{
   374  			name: "__go_print_nl",
   375  			rfi:  &ri.printNl,
   376  		},
   377  		{
   378  			name: "__go_print_pointer",
   379  			rfi:  &ri.printPointer,
   380  			args: []types.Type{UnsafePointer},
   381  		},
   382  		{
   383  			name: "__go_print_slice",
   384  			rfi:  &ri.printSlice,
   385  			args: []types.Type{IntSlice},
   386  		},
   387  		{
   388  			name: "__go_print_space",
   389  			rfi:  &ri.printSpace,
   390  		},
   391  		{
   392  			name: "__go_print_string",
   393  			rfi:  &ri.printString,
   394  			args: []types.Type{String},
   395  		},
   396  		{
   397  			name: "__go_print_uint64",
   398  			rfi:  &ri.printUint64,
   399  			args: []types.Type{Int64},
   400  		},
   401  		{
   402  			name: "__go_receive",
   403  			rfi:  &ri.receive,
   404  			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
   405  		},
   406  		{
   407  			name: "__go_recover",
   408  			rfi:  &ri.recover,
   409  			res:  []types.Type{EmptyInterface},
   410  		},
   411  		{
   412  			name: "__go_register_gc_roots",
   413  			rfi:  &ri.registerGcRoots,
   414  			args: []types.Type{UnsafePointer},
   415  		},
   416  		{
   417  			name:  "__go_runtime_error",
   418  			rfi:   &ri.runtimeError,
   419  			args:  []types.Type{Int32},
   420  			attrs: []llvm.Attribute{llvm.NoReturnAttribute},
   421  		},
   422  		{
   423  			name: "runtime.selectdefault",
   424  			rfi:  &ri.selectdefault,
   425  			args: []types.Type{UnsafePointer, Int32},
   426  		},
   427  		{
   428  			name: "runtime.selectgo",
   429  			rfi:  &ri.selectgo,
   430  			args: []types.Type{UnsafePointer},
   431  			res:  []types.Type{Int},
   432  		},
   433  		{
   434  			name: "runtime.selectrecv2",
   435  			rfi:  &ri.selectrecv2,
   436  			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, UnsafePointer, Int32},
   437  		},
   438  		{
   439  			name: "runtime.selectsend",
   440  			rfi:  &ri.selectsend,
   441  			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, Int32},
   442  		},
   443  		{
   444  			name: "__go_send_big",
   445  			rfi:  &ri.sendBig,
   446  			args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
   447  		},
   448  		{
   449  			name: "__go_set_defer_retaddr",
   450  			rfi:  &ri.setDeferRetaddr,
   451  			args: []types.Type{UnsafePointer},
   452  			res:  []types.Type{Bool},
   453  		},
   454  		{
   455  			name: "__go_strcmp",
   456  			rfi:  &ri.strcmp,
   457  			args: []types.Type{String, String},
   458  			res:  []types.Type{Int},
   459  		},
   460  		{
   461  			name: "__go_string_plus",
   462  			rfi:  &ri.stringPlus,
   463  			args: []types.Type{String, String},
   464  			res:  []types.Type{String},
   465  		},
   466  		{
   467  			name: "__go_string_slice",
   468  			rfi:  &ri.stringSlice,
   469  			args: []types.Type{String, Int, Int},
   470  			res:  []types.Type{String},
   471  		},
   472  		{
   473  			name:  "__go_string_to_byte_array",
   474  			rfi:   &ri.stringToByteArray,
   475  			args:  []types.Type{String},
   476  			res:   []types.Type{ByteSlice},
   477  			attrs: []llvm.Attribute{llvm.NoUnwindAttribute},
   478  		},
   479  		{
   480  			name: "__go_string_to_int_array",
   481  			rfi:  &ri.stringToIntArray,
   482  			args: []types.Type{String},
   483  			res:  []types.Type{IntSlice},
   484  		},
   485  		{
   486  			name: "runtime.stringiter2",
   487  			rfi:  &ri.stringiter2,
   488  			args: []types.Type{String, Int},
   489  			res:  []types.Type{Int, Rune},
   490  		},
   491  		{
   492  			name: "__go_type_descriptors_equal",
   493  			rfi:  &ri.typeDescriptorsEqual,
   494  			args: []types.Type{UnsafePointer, UnsafePointer},
   495  			res:  []types.Type{Bool},
   496  		},
   497  		{
   498  			name: "__go_undefer",
   499  			rfi:  &ri.undefer,
   500  			args: []types.Type{UnsafePointer},
   501  		},
   502  	} {
   503  		rt.rfi.init(tm, module, rt.name, rt.args, rt.res)
   504  		for _, attr := range rt.attrs {
   505  			rt.rfi.fn.AddFunctionAttr(attr)
   506  		}
   507  	}
   508  
   509  	memsetName := "llvm.memset.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth())
   510  	memsetType := llvm.FunctionType(
   511  		llvm.VoidType(),
   512  		[]llvm.Type{
   513  			llvm.PointerType(llvm.Int8Type(), 0),
   514  			llvm.Int8Type(),
   515  			tm.target.IntPtrType(),
   516  			llvm.Int32Type(),
   517  			llvm.Int1Type(),
   518  		},
   519  		false,
   520  	)
   521  	ri.memset = llvm.AddFunction(module, memsetName, memsetType)
   522  
   523  	memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth())
   524  	memcpyType := llvm.FunctionType(
   525  		llvm.VoidType(),
   526  		[]llvm.Type{
   527  			llvm.PointerType(llvm.Int8Type(), 0),
   528  			llvm.PointerType(llvm.Int8Type(), 0),
   529  			tm.target.IntPtrType(),
   530  			llvm.Int32Type(),
   531  			llvm.Int1Type(),
   532  		},
   533  		false,
   534  	)
   535  	ri.memcpy = llvm.AddFunction(module, memcpyName, memcpyType)
   536  
   537  	returnaddressType := llvm.FunctionType(
   538  		llvm.PointerType(llvm.Int8Type(), 0),
   539  		[]llvm.Type{llvm.Int32Type()},
   540  		false,
   541  	)
   542  	ri.returnaddress = llvm.AddFunction(module, "llvm.returnaddress", returnaddressType)
   543  
   544  	gccgoPersonalityType := llvm.FunctionType(
   545  		llvm.Int32Type(),
   546  		[]llvm.Type{
   547  			llvm.Int32Type(),
   548  			llvm.Int64Type(),
   549  			llvm.PointerType(llvm.Int8Type(), 0),
   550  			llvm.PointerType(llvm.Int8Type(), 0),
   551  		},
   552  		false,
   553  	)
   554  	ri.gccgoPersonality = llvm.AddFunction(module, "__gccgo_personality_v0", gccgoPersonalityType)
   555  
   556  	ri.gccgoExceptionType = llvm.StructType(
   557  		[]llvm.Type{
   558  			llvm.PointerType(llvm.Int8Type(), 0),
   559  			llvm.Int32Type(),
   560  		},
   561  		false,
   562  	)
   563  
   564  	return &ri, nil
   565  }
   566  
   567  func (fr *frame) createZExtOrTrunc(v llvm.Value, t llvm.Type, name string) llvm.Value {
   568  	switch n := v.Type().IntTypeWidth() - t.IntTypeWidth(); {
   569  	case n < 0:
   570  		v = fr.builder.CreateZExt(v, fr.target.IntPtrType(), name)
   571  	case n > 0:
   572  		v = fr.builder.CreateTrunc(v, fr.target.IntPtrType(), name)
   573  	}
   574  	return v
   575  }
   576  
   577  func (fr *frame) createTypeMalloc(t types.Type) llvm.Value {
   578  	size := llvm.ConstInt(fr.target.IntPtrType(), uint64(fr.llvmtypes.Sizeof(t)), false)
   579  	malloc := fr.runtime.New.callOnly(fr, fr.types.ToRuntime(t), size)[0]
   580  	return fr.builder.CreateBitCast(malloc, llvm.PointerType(fr.types.ToLLVM(t), 0), "")
   581  }
   582  
   583  func (fr *frame) memsetZero(ptr llvm.Value, size llvm.Value) {
   584  	memset := fr.runtime.memset
   585  	ptr = fr.builder.CreateBitCast(ptr, llvm.PointerType(llvm.Int8Type(), 0), "")
   586  	fill := llvm.ConstNull(llvm.Int8Type())
   587  	size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "")
   588  	align := llvm.ConstInt(llvm.Int32Type(), 1, false)
   589  	isvolatile := llvm.ConstNull(llvm.Int1Type())
   590  	fr.builder.CreateCall(memset, []llvm.Value{ptr, fill, size, align, isvolatile}, "")
   591  }
   592  
   593  func (fr *frame) memcpy(dest llvm.Value, src llvm.Value, size llvm.Value) {
   594  	memcpy := fr.runtime.memcpy
   595  	dest = fr.builder.CreateBitCast(dest, llvm.PointerType(llvm.Int8Type(), 0), "")
   596  	src = fr.builder.CreateBitCast(src, llvm.PointerType(llvm.Int8Type(), 0), "")
   597  	size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "")
   598  	align := llvm.ConstInt(llvm.Int32Type(), 1, false)
   599  	isvolatile := llvm.ConstNull(llvm.Int1Type())
   600  	fr.builder.CreateCall(memcpy, []llvm.Value{dest, src, size, align, isvolatile}, "")
   601  }
   602  
   603  func (fr *frame) returnAddress(level uint64) llvm.Value {
   604  	returnaddress := fr.runtime.returnaddress
   605  	levelValue := llvm.ConstInt(llvm.Int32Type(), level, false)
   606  	return fr.builder.CreateCall(returnaddress, []llvm.Value{levelValue}, "")
   607  }