compiler: refactor and add tests

This commit finally introduces unit tests for the compiler, to check
whether input Go code is converted to the expected output IR.

To make this necessary, a few refactors were needed. Hopefully these
refactors (to compile a program package by package instead of all at
once) will eventually become standard, so that packages can all be
compiled separate from each other and be cached between compiles.
This commit is contained in:
Ayke van Laethem
2021-01-13 17:22:13 +01:00
committed by Ron Evans
parent dbc438b2ae
commit a848d720db
12 changed files with 610 additions and 100 deletions
+57
View File
@@ -0,0 +1,57 @@
package main
// Basic tests that don't need to be split into a separate file.
func addInt(x, y int) int {
return x + y
}
func equalInt(x, y int) bool {
return x == y
}
func floatEQ(x, y float32) bool {
return x == y
}
func floatNE(x, y float32) bool {
return x != y
}
func floatLower(x, y float32) bool {
return x < y
}
func floatLowerEqual(x, y float32) bool {
return x <= y
}
func floatGreater(x, y float32) bool {
return x > y
}
func floatGreaterEqual(x, y float32) bool {
return x >= y
}
func complexReal(x complex64) float32 {
return real(x)
}
func complexImag(x complex64) float32 {
return imag(x)
}
func complexAdd(x, y complex64) complex64 {
return x + y
}
func complexSub(x, y complex64) complex64 {
return x - y
}
func complexMul(x, y complex64) complex64 {
return x * y
}
// TODO: complexDiv (requires runtime call)
+98
View File
@@ -0,0 +1,98 @@
; ModuleID = 'basic.go'
source_filename = "basic.go"
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
target triple = "i686--linux"
define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret void
}
define internal i32 @main.addInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = add i32 %x, %y
ret i32 %0
}
define internal i1 @main.equalInt(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = icmp eq i32 %x, %y
ret i1 %0
}
define internal i1 @main.floatEQ(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = fcmp oeq float %x, %y
ret i1 %0
}
define internal i1 @main.floatNE(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = fcmp une float %x, %y
ret i1 %0
}
define internal i1 @main.floatLower(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = fcmp olt float %x, %y
ret i1 %0
}
define internal i1 @main.floatLowerEqual(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = fcmp ole float %x, %y
ret i1 %0
}
define internal i1 @main.floatGreater(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = fcmp ogt float %x, %y
ret i1 %0
}
define internal i1 @main.floatGreaterEqual(float %x, float %y, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = fcmp oge float %x, %y
ret i1 %0
}
define internal float @main.complexReal(float %x.r, float %x.i, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret float %x.r
}
define internal float @main.complexImag(float %x.r, float %x.i, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret float %x.i
}
define internal { float, float } @main.complexAdd(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = fadd float %x.r, %y.r
%1 = fadd float %x.i, %y.i
%2 = insertvalue { float, float } undef, float %0, 0
%3 = insertvalue { float, float } %2, float %1, 1
ret { float, float } %3
}
define internal { float, float } @main.complexSub(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = fsub float %x.r, %y.r
%1 = fsub float %x.i, %y.i
%2 = insertvalue { float, float } undef, float %0, 0
%3 = insertvalue { float, float } %2, float %1, 1
ret { float, float } %3
}
define internal { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = fmul float %x.r, %y.r
%1 = fmul float %x.i, %y.i
%2 = fsub float %0, %1
%3 = fmul float %x.r, %y.i
%4 = fmul float %x.i, %y.r
%5 = fadd float %3, %4
%6 = insertvalue { float, float } undef, float %2, 0
%7 = insertvalue { float, float } %6, float %5, 1
ret { float, float } %7
}
+41
View File
@@ -0,0 +1,41 @@
package main
// This file tests various operations on pointers, such as pointer arithmetic
// and dereferencing pointers.
import "unsafe"
// Dereference pointers.
func pointerDerefZero(x *[0]int) [0]int {
return *x // This is a no-op, there is nothing to load.
}
// Unsafe pointer casts, they are sometimes a no-op.
func pointerCastFromUnsafe(x unsafe.Pointer) *int {
return (*int)(x)
}
func pointerCastToUnsafe(x *int) unsafe.Pointer {
return unsafe.Pointer(x)
}
func pointerCastToUnsafeNoop(x *byte) unsafe.Pointer {
return unsafe.Pointer(x)
}
// The compiler has support for a few special cast+add patterns that are
// transformed into a single GEP.
func pointerUnsafeGEPFixedOffset(ptr *byte) *byte {
return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + 10))
}
func pointerUnsafeGEPByteOffset(ptr *byte, offset uintptr) *byte {
return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + offset))
}
func pointerUnsafeGEPIntOffset(ptr *int32, offset uintptr) *int32 {
return (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + offset*4))
}
+49
View File
@@ -0,0 +1,49 @@
; ModuleID = 'pointer.go'
source_filename = "pointer.go"
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
target triple = "i686--linux"
define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret void
}
define internal [0 x i32] @main.pointerDerefZero([0 x i32]* %x, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret [0 x i32] zeroinitializer
}
define internal i32* @main.pointerCastFromUnsafe(i8* %x, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = bitcast i8* %x to i32*
ret i32* %0
}
define internal i8* @main.pointerCastToUnsafe(i32* dereferenceable_or_null(4) %x, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = bitcast i32* %x to i8*
ret i8* %0
}
define internal i8* @main.pointerCastToUnsafeNoop(i8* dereferenceable_or_null(1) %x, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret i8* %x
}
define internal i8* @main.pointerUnsafeGEPFixedOffset(i8* dereferenceable_or_null(1) %ptr, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = getelementptr inbounds i8, i8* %ptr, i32 10
ret i8* %0
}
define internal i8* @main.pointerUnsafeGEPByteOffset(i8* dereferenceable_or_null(1) %ptr, i32 %offset, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = getelementptr inbounds i8, i8* %ptr, i32 %offset
ret i8* %0
}
define internal i32* @main.pointerUnsafeGEPIntOffset(i32* dereferenceable_or_null(4) %ptr, i32 %offset, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = getelementptr i32, i32* %ptr, i32 %offset
ret i32* %0
}
+9
View File
@@ -0,0 +1,9 @@
package main
func sliceLen(ints []int) int {
return len(ints)
}
func sliceCap(ints []int) int {
return cap(ints)
}
+19
View File
@@ -0,0 +1,19 @@
; ModuleID = 'slice.go'
source_filename = "slice.go"
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
target triple = "i686--linux"
define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret void
}
define internal i32 @main.sliceLen(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret i32 %ints.len
}
define internal i32 @main.sliceCap(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret i32 %ints.cap
}