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 }