tinygo/transform/reflect_test.go
Ayke van Laethem cd517a30af transform: split interface and reflect lowering
These two passes are related, but can definitely work independently.
Which is what this change does: it splits the two passes. This should
make it easier to change these two new passes in the future.

This change now also enables slightly better testing by testing these
two passes independently. In particular, the reflect lowering pass got
some actual tests: it was barely unit-tested before.

I have verified that this doesn't really change code size, at least not
on the microbit target. Two tests do change, but in a very minor way
(and in opposite direction).
2021-05-03 20:10:49 +02:00

77 строки
2,3 КиБ
Go

package transform_test
import (
"testing"
"github.com/tinygo-org/tinygo/transform"
"tinygo.org/x/go-llvm"
)
type reflectAssert struct {
call llvm.Value
name string
expectedNumber uint64
}
// Test reflect lowering. This code looks at IR like this:
//
// call void @main.assertType(i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:int" to i32), i8* inttoptr (i32 3 to i8*), i32 4, i8* undef, i8* undef)
//
// and verifies that the ptrtoint constant (the first parameter of
// @main.assertType) is replaced with the correct type code. The expected
// output is this:
//
// call void @main.assertType(i32 4, i8* inttoptr (i32 3 to i8*), i32 4, i8* undef, i8* undef)
//
// The first and third parameter are compared and must match, the second
// parameter is ignored.
func TestReflect(t *testing.T) {
t.Parallel()
mod := compileGoFileForTesting(t, "./testdata/reflect.go")
// Run the instcombine pass, to clean up the IR a bit (especially
// insertvalue/extractvalue instructions).
pm := llvm.NewPassManager()
defer pm.Dispose()
pm.AddInstructionCombiningPass()
pm.Run(mod)
// Get a list of all the asserts in the source code.
assertType := mod.NamedFunction("main.assertType")
var asserts []reflectAssert
for user := assertType.FirstUse(); !user.IsNil(); user = user.NextUse() {
use := user.User()
if use.IsACallInst().IsNil() {
t.Fatal("expected call use of main.assertType")
}
global := use.Operand(0).Operand(0)
expectedNumber := use.Operand(2).ZExtValue()
asserts = append(asserts, reflectAssert{
call: use,
name: global.Name(),
expectedNumber: expectedNumber,
})
}
// Sanity check to show that the test is actually testing anything.
if len(asserts) < 3 {
t.Errorf("expected at least 3 test cases, got %d", len(asserts))
}
// Now lower the type codes.
transform.LowerReflect(mod)
// Check whether the values are as expected.
for _, assert := range asserts {
actualNumberValue := assert.call.Operand(0)
if actualNumberValue.IsAConstantInt().IsNil() {
t.Errorf("expected to see a constant for %s, got something else", assert.name)
continue
}
actualNumber := actualNumberValue.ZExtValue()
if actualNumber != assert.expectedNumber {
t.Errorf("%s: expected number 0b%b, got 0b%b", assert.name, assert.expectedNumber, actualNumber)
}
}
}