package ssa import ( "testing" ) func TestFuseEliminatesOneBranch(t *testing.T) { ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"), Valu("nilptr", OpConstNil, ptrType, 0, nil, "sb"), Valu("bool1", OpNeqPtr, TypeBool, 0, nil, "ptr1", "nilptr"), If("bool1", "then", "exit")), Bloc("then", Goto("exit")), Bloc("exit", Exit("mem"))) CheckFunc(fun.f) fuse(fun.f) for _, b := range fun.f.Blocks { if b == fun.blocks["then"] && b.Kind != BlockInvalid { t.Errorf("then was not eliminated, but should have") } } } func TestFuseEliminatesBothBranches(t *testing.T) { ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"), Valu("nilptr", OpConstNil, ptrType, 0, nil, "sb"), Valu("bool1", OpNeqPtr, TypeBool, 0, nil, "ptr1", "nilptr"), If("bool1", "then", "else")), Bloc("then", Goto("exit")), Bloc("else", Goto("exit")), Bloc("exit", Exit("mem"))) CheckFunc(fun.f) fuse(fun.f) for _, b := range fun.f.Blocks { if b == fun.blocks["then"] && b.Kind != BlockInvalid { t.Errorf("then was not eliminated, but should have") } if b == fun.blocks["else"] && b.Kind != BlockInvalid { t.Errorf("then was not eliminated, but should have") } } } func TestFuseHandlesPhis(t *testing.T) { ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"), Valu("nilptr", OpConstNil, ptrType, 0, nil, "sb"), Valu("bool1", OpNeqPtr, TypeBool, 0, nil, "ptr1", "nilptr"), If("bool1", "then", "else")), Bloc("then", Goto("exit")), Bloc("else", Goto("exit")), Bloc("exit", Valu("phi", OpPhi, ptrType, 0, nil, "ptr1", "ptr1"), Exit("mem"))) CheckFunc(fun.f) fuse(fun.f) for _, b := range fun.f.Blocks { if b == fun.blocks["then"] && b.Kind != BlockInvalid { t.Errorf("then was not eliminated, but should have") } if b == fun.blocks["else"] && b.Kind != BlockInvalid { t.Errorf("then was not eliminated, but should have") } } } func TestFuseEliminatesEmptyBlocks(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("z0")), Bloc("z1", Goto("z2")), Bloc("z3", Goto("exit")), Bloc("z2", Goto("z3")), Bloc("z0", Goto("z1")), Bloc("exit", Exit("mem"), )) CheckFunc(fun.f) fuse(fun.f) for k, b := range fun.blocks { if k[:1] == "z" && b.Kind != BlockInvalid { t.Errorf("%s was not eliminated, but should have", k) } } }