github.com/goplus/llgo@v0.8.3/ssa/ssa_test.go (about)

     1  /*
     2   * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package ssa
    18  
    19  import (
    20  	"go/constant"
    21  	"go/token"
    22  	"go/types"
    23  	"testing"
    24  
    25  	"github.com/goplus/llvm"
    26  )
    27  
    28  func TestSetBlock(t *testing.T) {
    29  	defer func() {
    30  		if r := recover(); r == nil {
    31  			t.Log("SetBlock: no error?")
    32  		}
    33  	}()
    34  	fn := &aFunction{}
    35  	b := &aBuilder{Func: fn}
    36  	b.SetBlock(&aBasicBlock{})
    37  }
    38  
    39  func TestSetBlockEx(t *testing.T) {
    40  	defer func() {
    41  		if r := recover(); r == nil {
    42  			t.Log("SetBlockEx: no error?")
    43  		}
    44  	}()
    45  	fn := &aFunction{}
    46  	b := &aBuilder{Func: fn}
    47  	b.SetBlockEx(&aBasicBlock{fn: fn}, -1)
    48  }
    49  
    50  func TestSetPython(t *testing.T) {
    51  	prog := NewProgram(nil)
    52  	typ := types.NewPackage("foo", "foo")
    53  	prog.SetPython(typ)
    54  }
    55  
    56  func TestClosureCtx(t *testing.T) {
    57  	defer func() {
    58  		if r := recover(); r == nil {
    59  			t.Log("closureCtx: no error?")
    60  		}
    61  	}()
    62  	var f aFunction
    63  	f.closureCtx(nil)
    64  }
    65  
    66  func TestTypes(t *testing.T) {
    67  	ctx := llvm.NewContext()
    68  	llvmIntType(ctx, 4)
    69  
    70  	intT := types.NewVar(0, nil, "", types.Typ[types.Int])
    71  	ret := types.NewTuple(intT, intT)
    72  	sig := types.NewSignatureType(nil, nil, nil, nil, ret, false)
    73  	prog := NewProgram(nil)
    74  	prog.retType(sig)
    75  }
    76  
    77  func TestIndexType(t *testing.T) {
    78  	defer func() {
    79  		if r := recover(); r == nil {
    80  			t.Log("indexType: no error?")
    81  		}
    82  	}()
    83  	indexType(types.Typ[types.Int])
    84  }
    85  
    86  func TestCvtType(t *testing.T) {
    87  	gt := newGoTypes()
    88  	callback := types.NewSignatureType(nil, nil, nil, nil, nil, false)
    89  	params := types.NewTuple(types.NewParam(0, nil, "", callback))
    90  	sig := types.NewSignatureType(nil, nil, nil, params, nil, false)
    91  	ret1 := gt.cvtFunc(sig, nil)
    92  	if ret1 == sig {
    93  		t.Fatal("cvtFunc failed")
    94  	}
    95  	defer func() {
    96  		if r := recover(); r == nil {
    97  			t.Log("cvtType: no error?")
    98  		}
    99  	}()
   100  	gt.cvtType(nil)
   101  }
   102  
   103  func TestUserdefExpr(t *testing.T) {
   104  	b := &phisExprTy{}
   105  	c := &pyVarTy{}
   106  	_ = b.String()
   107  	_ = c.String()
   108  	test := func(a types.Type) {
   109  		defer func() {
   110  			if r := recover(); r == nil {
   111  				t.Log("TestUserdefExpr: no error?")
   112  			}
   113  		}()
   114  		a.Underlying()
   115  	}
   116  	test(b)
   117  	test(c)
   118  }
   119  
   120  func TestAny(t *testing.T) {
   121  	prog := NewProgram(nil)
   122  	prog.SetRuntime(func() *types.Package {
   123  		ret := types.NewPackage("runtime", "runtime")
   124  		scope := ret.Scope()
   125  		name := types.NewTypeName(0, ret, "Interface", nil)
   126  		types.NewNamed(name, types.NewStruct(nil, nil), nil)
   127  		scope.Insert(name)
   128  		return ret
   129  	})
   130  	prog.Any()
   131  }
   132  
   133  func assertPkg(t *testing.T, p Package, expected string) {
   134  	t.Helper()
   135  	if v := p.String(); v != expected {
   136  		t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
   137  	}
   138  }
   139  
   140  func TestPyFunc(t *testing.T) {
   141  	prog := NewProgram(nil)
   142  	py := types.NewPackage("foo", "foo")
   143  	o := types.NewTypeName(0, py, "Object", nil)
   144  	types.NewNamed(o, types.Typ[types.Int], nil)
   145  	py.Scope().Insert(o)
   146  	prog.SetPython(py)
   147  	pkg := prog.NewPackage("bar", "foo/bar")
   148  	sig := types.NewSignatureType(nil, nil, nil, nil, nil, false)
   149  	a := pkg.PyNewFunc("a", sig, false)
   150  	if pkg.PyNewFunc("a", sig, false) != a {
   151  		t.Fatal("NewPyFunc(a) failed")
   152  	}
   153  	foo := pkg.PyNewModVar("foo", false)
   154  	if pkg.PyNewModVar("foo", false) != foo {
   155  		t.Fatal("NewPyModVar(foo) failed")
   156  	}
   157  }
   158  
   159  func TestVar(t *testing.T) {
   160  	prog := NewProgram(nil)
   161  	pkg := prog.NewPackage("bar", "foo/bar")
   162  	a := pkg.NewVar("a", types.Typ[types.Int], InGo)
   163  	if pkg.NewVar("a", types.Typ[types.Int], InGo) != a {
   164  		t.Fatal("NewVar(a) failed")
   165  	}
   166  	a.Init(prog.Val(100))
   167  	b := pkg.NewVar("b", types.Typ[types.Int], InGo)
   168  	b.Init(a.Expr)
   169  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   170  source_filename = "foo/bar"
   171  
   172  @a = global i64 100
   173  @b = global i64 @a
   174  `)
   175  }
   176  
   177  func TestConst(t *testing.T) {
   178  	prog := NewProgram(nil)
   179  	pkg := prog.NewPackage("bar", "foo/bar")
   180  	rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Bool]))
   181  	sig := types.NewSignatureType(nil, nil, nil, nil, rets, false)
   182  	b := pkg.NewFunc("fn", sig, InGo).MakeBody(1)
   183  	b.Return(b.Const(constant.MakeBool(true), prog.Bool()))
   184  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   185  source_filename = "foo/bar"
   186  
   187  define i1 @fn() {
   188  _llgo_0:
   189    ret i1 true
   190  }
   191  `)
   192  }
   193  
   194  func TestStruct(t *testing.T) {
   195  	empty := types.NewStruct(nil, nil)
   196  
   197  	prog := NewProgram(nil)
   198  	pkg := prog.NewPackage("bar", "foo/bar")
   199  	pkg.NewVar("a", empty, InGo)
   200  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   201  source_filename = "foo/bar"
   202  
   203  @a = external global {}
   204  `)
   205  	if prog.NeedRuntime {
   206  		t.Fatal("NeedRuntime?")
   207  	}
   208  }
   209  
   210  func TestNamedStruct(t *testing.T) {
   211  	src := types.NewPackage("bar", "foo/bar")
   212  	empty := types.NewNamed(types.NewTypeName(0, src, "Empty", nil), types.NewStruct(nil, nil), nil)
   213  
   214  	prog := NewProgram(nil)
   215  	pkg := prog.NewPackage("bar", "foo/bar")
   216  	pkg.NewVar("a", empty, InGo)
   217  	if pkg.VarOf("a") == nil {
   218  		t.Fatal("VarOf failed")
   219  	}
   220  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   221  source_filename = "foo/bar"
   222  
   223  %bar.Empty = type {}
   224  
   225  @a = external global %bar.Empty
   226  `)
   227  }
   228  
   229  func TestDeclFunc(t *testing.T) {
   230  	prog := NewProgram(nil)
   231  	pkg := prog.NewPackage("bar", "foo/bar")
   232  	params := types.NewTuple(types.NewVar(0, nil, "a", types.Typ[types.Int]))
   233  	sig := types.NewSignatureType(nil, nil, nil, params, nil, false)
   234  	pkg.NewFunc("fn", sig, InGo)
   235  	if pkg.FuncOf("fn") == nil {
   236  		t.Fatal("FuncOf failed")
   237  	}
   238  	if prog.retType(sig) != prog.Void() {
   239  		t.Fatal("retType failed")
   240  	}
   241  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   242  source_filename = "foo/bar"
   243  
   244  declare void @fn(i64)
   245  `)
   246  }
   247  
   248  func TestBasicFunc(t *testing.T) {
   249  	prog := NewProgram(nil)
   250  	pkg := prog.NewPackage("bar", "foo/bar")
   251  	params := types.NewTuple(
   252  		types.NewVar(0, nil, "a", types.Typ[types.Int]),
   253  		types.NewVar(0, nil, "b", types.Typ[types.Float64]))
   254  	rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
   255  	sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
   256  	pkg.NewFunc("fn", sig, InGo).MakeBody(1).
   257  		Return(prog.Val(1))
   258  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   259  source_filename = "foo/bar"
   260  
   261  define i64 @fn(i64 %0, double %1) {
   262  _llgo_0:
   263    ret i64 1
   264  }
   265  `)
   266  }
   267  
   268  func TestFuncParam(t *testing.T) {
   269  	prog := NewProgram(nil)
   270  	pkg := prog.NewPackage("bar", "foo/bar")
   271  	params := types.NewTuple(
   272  		types.NewVar(0, nil, "a", types.Typ[types.Int]),
   273  		types.NewVar(0, nil, "b", types.Typ[types.Float64]))
   274  	rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
   275  	sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
   276  	fn := pkg.NewFunc("fn", sig, InGo)
   277  	fn.MakeBody(1).Return(fn.Param(0))
   278  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   279  source_filename = "foo/bar"
   280  
   281  define i64 @fn(i64 %0, double %1) {
   282  _llgo_0:
   283    ret i64 %0
   284  }
   285  `)
   286  }
   287  
   288  func TestFuncCall(t *testing.T) {
   289  	prog := NewProgram(nil)
   290  	pkg := prog.NewPackage("bar", "foo/bar")
   291  
   292  	params := types.NewTuple(
   293  		types.NewVar(0, nil, "a", types.Typ[types.Int]),
   294  		types.NewVar(0, nil, "b", types.Typ[types.Float64]))
   295  	rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
   296  	sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
   297  	fn := pkg.NewFunc("fn", sig, InGo)
   298  	fn.MakeBody(1).
   299  		Return(prog.Val(1))
   300  
   301  	sigMain := types.NewSignatureType(nil, nil, nil, nil, nil, false)
   302  	b := pkg.NewFunc("main", sigMain, InGo).MakeBody(1)
   303  	b.Call(fn.Expr, prog.Val(1), prog.Val(1.2))
   304  	b.Return()
   305  
   306  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   307  source_filename = "foo/bar"
   308  
   309  define i64 @fn(i64 %0, double %1) {
   310  _llgo_0:
   311    ret i64 1
   312  }
   313  
   314  define void @main() {
   315  _llgo_0:
   316    %0 = call i64 @fn(i64 1, double 1.200000e+00)
   317    ret void
   318  }
   319  `)
   320  }
   321  
   322  func TestFuncMultiRet(t *testing.T) {
   323  	prog := NewProgram(nil)
   324  	pkg := prog.NewPackage("bar", "foo/bar")
   325  	params := types.NewTuple(
   326  		types.NewVar(0, nil, "b", types.Typ[types.Float64]))
   327  	rets := types.NewTuple(
   328  		types.NewVar(0, nil, "c", types.Typ[types.Int]),
   329  		types.NewVar(0, nil, "d", types.Typ[types.Float64]))
   330  	sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
   331  	a := pkg.NewVar("a", types.Typ[types.Int], InGo)
   332  	fn := pkg.NewFunc("fn", sig, InGo)
   333  	b := fn.MakeBody(1)
   334  	b.Return(a.Expr, fn.Param(0))
   335  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   336  source_filename = "foo/bar"
   337  
   338  @a = external global i64
   339  
   340  define { i64, double } @fn(double %0) {
   341  _llgo_0:
   342    %mrv = insertvalue { i64, double } { ptr @a, double poison }, double %0, 1
   343    ret { i64, double } %mrv
   344  }
   345  `)
   346  }
   347  
   348  func TestJump(t *testing.T) {
   349  	prog := NewProgram(nil)
   350  	pkg := prog.NewPackage("bar", "foo/bar")
   351  	sig := types.NewSignatureType(nil, nil, nil, nil, nil, false)
   352  	fn := pkg.NewFunc("loop", sig, InGo)
   353  	b := fn.MakeBody(1)
   354  	b.Jump(fn.Block(0))
   355  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   356  source_filename = "foo/bar"
   357  
   358  define void @loop() {
   359  _llgo_0:
   360    br label %_llgo_0
   361  }
   362  `)
   363  }
   364  
   365  func TestIf(t *testing.T) {
   366  	prog := NewProgram(nil)
   367  	pkg := prog.NewPackage("bar", "foo/bar")
   368  	params := types.NewTuple(types.NewVar(0, nil, "a", types.Typ[types.Int]))
   369  	rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
   370  	sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
   371  	fn := pkg.NewFunc("fn", sig, InGo)
   372  	b := fn.MakeBody(3)
   373  	iftrue := fn.Block(1)
   374  	iffalse := fn.Block(2)
   375  	if iftrue.Index() != 1 || iftrue.Parent() != fn {
   376  		t.Fatal("iftrue")
   377  	}
   378  	cond := b.BinOp(token.GTR, fn.Param(0), prog.Val(0))
   379  	b.If(cond, iftrue, iffalse)
   380  	b.SetBlock(iftrue).Return(prog.Val(1))
   381  	b.SetBlock(iffalse).Return(prog.Val(0))
   382  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   383  source_filename = "foo/bar"
   384  
   385  define i64 @fn(i64 %0) {
   386  _llgo_0:
   387    %1 = icmp sgt i64 %0, 0
   388    br i1 %1, label %_llgo_1, label %_llgo_2
   389  
   390  _llgo_1:                                          ; preds = %_llgo_0
   391    ret i64 1
   392  
   393  _llgo_2:                                          ; preds = %_llgo_0
   394    ret i64 0
   395  }
   396  `)
   397  }
   398  
   399  func TestPrintf(t *testing.T) {
   400  	prog := NewProgram(nil)
   401  	pkg := prog.NewPackage("bar", "foo/bar")
   402  	pchar := types.NewPointer(types.Typ[types.Int8])
   403  	params := types.NewTuple(types.NewVar(0, nil, "format", pchar), VArg())
   404  	rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int32]))
   405  	sig := types.NewSignatureType(nil, nil, nil, params, rets, true)
   406  	pkg.NewFunc("printf", sig, InC)
   407  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   408  source_filename = "foo/bar"
   409  
   410  declare i32 @printf(ptr, ...)
   411  `)
   412  }
   413  
   414  func TestBinOp(t *testing.T) {
   415  	prog := NewProgram(nil)
   416  	pkg := prog.NewPackage("bar", "foo/bar")
   417  	params := types.NewTuple(
   418  		types.NewVar(0, nil, "a", types.Typ[types.Int]),
   419  		types.NewVar(0, nil, "b", types.Typ[types.Float64]))
   420  	rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
   421  	sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
   422  	fn := pkg.NewFunc("fn", sig, InGo)
   423  	b := fn.MakeBody(1)
   424  	ret := b.BinOp(token.ADD, fn.Param(0), prog.Val(1))
   425  	b.Return(ret)
   426  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   427  source_filename = "foo/bar"
   428  
   429  define i64 @fn(i64 %0, double %1) {
   430  _llgo_0:
   431    %2 = add i64 %0, 1
   432    ret i64 %2
   433  }
   434  `)
   435  }
   436  
   437  func TestUnOp(t *testing.T) {
   438  	prog := NewProgram(nil)
   439  	pkg := prog.NewPackage("bar", "foo/bar")
   440  	params := types.NewTuple(
   441  		types.NewVar(0, nil, "p", types.NewPointer(types.Typ[types.Int])),
   442  	)
   443  	rets := types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int]))
   444  	sig := types.NewSignatureType(nil, nil, nil, params, rets, false)
   445  	fn := pkg.NewFunc("fn", sig, InGo)
   446  	b := fn.MakeBody(1)
   447  	ptr := fn.Param(0)
   448  	val := b.UnOp(token.MUL, ptr)
   449  	val2 := b.BinOp(token.XOR, val, prog.Val(1))
   450  	b.Store(ptr, val2)
   451  	b.Return(val2)
   452  	assertPkg(t, pkg, `; ModuleID = 'foo/bar'
   453  source_filename = "foo/bar"
   454  
   455  define i64 @fn(ptr %0) {
   456  _llgo_0:
   457    %1 = load i64, ptr %0, align 4
   458    %2 = xor i64 %1, 1
   459    store i64 %2, ptr %0, align 4
   460    ret i64 %2
   461  }
   462  `)
   463  }
   464  
   465  func TestBasicType(t *testing.T) {
   466  	type typeInfo struct {
   467  		typ  Type
   468  		kind types.BasicKind
   469  	}
   470  	prog := NewProgram(nil)
   471  	infos := []*typeInfo{
   472  		{prog.Bool(), types.Bool},
   473  		{prog.Byte(), types.Byte},
   474  		{prog.Int(), types.Int},
   475  		{prog.Uint(), types.Uint},
   476  		{prog.Int32(), types.Int32},
   477  		{prog.Int64(), types.Int64},
   478  		{prog.Uint32(), types.Uint32},
   479  		{prog.Uint64(), types.Uint64},
   480  		{prog.Uintptr(), types.Uintptr},
   481  		{prog.VoidPtr(), types.UnsafePointer},
   482  	}
   483  	for _, info := range infos {
   484  		if info.typ.RawType() != types.Typ[info.kind] {
   485  			t.Fatal("bad type", info)
   486  		}
   487  	}
   488  }