Этот коммит содержится в:
Ayke van Laethem 2018-09-20 20:52:59 +02:00
родитель 45348bfc3e
коммит dbb5ae5a23
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
4 изменённых файлов: 52 добавлений и 13 удалений

Просмотреть файл

@ -105,8 +105,13 @@ func NewCompiler(pkgName, triple string, dumpSSA bool) (*Compiler, error) {
// Depends on platform (32bit or 64bit), but fix it here for now. // Depends on platform (32bit or 64bit), but fix it here for now.
c.intType = llvm.Int32Type() c.intType = llvm.Int32Type()
c.lenType = llvm.Int32Type() // also defined as runtime.lenType
c.uintptrType = c.targetData.IntPtrType() c.uintptrType = c.targetData.IntPtrType()
if c.targetData.PointerSize() < 4 {
// 16 or 8 bits target with smaller length type
c.lenType = c.uintptrType
} else {
c.lenType = llvm.Int32Type() // also defined as runtime.lenType
}
c.i8ptrType = llvm.PointerType(llvm.Int8Type(), 0) c.i8ptrType = llvm.PointerType(llvm.Int8Type(), 0)
allocType := llvm.FunctionType(c.i8ptrType, []llvm.Type{c.uintptrType}, false) allocType := llvm.FunctionType(c.i8ptrType, []llvm.Type{c.uintptrType}, false)
@ -1632,20 +1637,25 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string)
if err != nil { if err != nil {
return llvm.Value{}, err return llvm.Value{}, err
} }
var llvmLen llvm.Value
switch args[0].Type().(type) { switch args[0].Type().(type) {
case *types.Basic, *types.Slice: case *types.Basic, *types.Slice:
// string or slice // string or slice
return c.builder.CreateExtractValue(value, 1, "len"), nil llvmLen = c.builder.CreateExtractValue(value, 1, "len")
case *types.Map: case *types.Map:
indices := []llvm.Value{ indices := []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(llvm.Int32Type(), 2, false), // hashmap.count llvm.ConstInt(llvm.Int32Type(), 2, false), // hashmap.count
} }
ptr := c.builder.CreateGEP(value, indices, "lenptr") ptr := c.builder.CreateGEP(value, indices, "lenptr")
return c.builder.CreateLoad(ptr, "len"), nil llvmLen = c.builder.CreateLoad(ptr, "len")
default: default:
return llvm.Value{}, errors.New("todo: len: unknown type") return llvm.Value{}, errors.New("todo: len: unknown type")
} }
if c.targetData.TypeAllocSize(llvmLen.Type()) < c.targetData.TypeAllocSize(c.intType) {
llvmLen = c.builder.CreateZExt(llvmLen, c.intType, "len.int")
}
return llvmLen, nil
case "print", "println": case "print", "println":
for i, arg := range args { for i, arg := range args {
if i >= 1 && callName == "println" { if i >= 1 && callName == "println" {
@ -2041,7 +2051,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// Check bounds. // Check bounds.
arrayLen := expr.X.Type().(*types.Array).Len() arrayLen := expr.X.Type().(*types.Array).Len()
arrayLenLLVM := llvm.ConstInt(llvm.Int32Type(), uint64(arrayLen), false) arrayLenLLVM := llvm.ConstInt(c.lenType, uint64(arrayLen), false)
c.emitBoundsCheck(frame, arrayLenLLVM, index) c.emitBoundsCheck(frame, arrayLenLLVM, index)
// Can't load directly from array (as index is non-constant), so have to // Can't load directly from array (as index is non-constant), so have to
@ -2069,7 +2079,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
switch typ := typ.(type) { switch typ := typ.(type) {
case *types.Array: case *types.Array:
bufptr = val bufptr = val
buflen = llvm.ConstInt(llvm.Int32Type(), uint64(typ.Len()), false) buflen = llvm.ConstInt(c.lenType, uint64(typ.Len()), false)
default: default:
return llvm.Value{}, errors.New("todo: indexaddr: " + typ.String()) return llvm.Value{}, errors.New("todo: indexaddr: " + typ.String())
} }
@ -2218,6 +2228,11 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
slicePtr := c.builder.CreateCall(c.allocFunc, []llvm.Value{sliceSize}, "makeslice.buf") slicePtr := c.builder.CreateCall(c.allocFunc, []llvm.Value{sliceSize}, "makeslice.buf")
slicePtr = c.builder.CreateBitCast(slicePtr, llvm.PointerType(llvmElemType, 0), "makeslice.array") slicePtr = c.builder.CreateBitCast(slicePtr, llvm.PointerType(llvmElemType, 0), "makeslice.array")
if c.targetData.TypeAllocSize(sliceLen.Type()) > c.targetData.TypeAllocSize(c.lenType) {
sliceLen = c.builder.CreateTrunc(sliceLen, c.lenType, "")
sliceCap = c.builder.CreateTrunc(sliceCap, c.lenType, "")
}
// Create the slice. // Create the slice.
slice := llvm.ConstStruct([]llvm.Value{ slice := llvm.ConstStruct([]llvm.Value{
llvm.Undef(slicePtr.Type()), llvm.Undef(slicePtr.Type()),
@ -2299,7 +2314,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
} }
var low, high llvm.Value var low, high llvm.Value
if expr.Low == nil { if expr.Low == nil {
low = llvm.ConstInt(c.lenType, 0, false) low = llvm.ConstInt(c.intType, 0, false)
} else { } else {
low, err = c.parseExpr(frame, expr.Low) low, err = c.parseExpr(frame, expr.Low)
if err != nil { if err != nil {
@ -2317,8 +2332,9 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// slice an array // slice an array
length := typ.Elem().(*types.Array).Len() length := typ.Elem().(*types.Array).Len()
llvmLen := llvm.ConstInt(c.lenType, uint64(length), false) llvmLen := llvm.ConstInt(c.lenType, uint64(length), false)
llvmLenInt := llvm.ConstInt(c.intType, uint64(length), false)
if high.IsNil() { if high.IsNil() {
high = llvmLen high = llvmLenInt
} }
indices := []llvm.Value{ indices := []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), 0, false),
@ -2326,7 +2342,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
} }
slicePtr := c.builder.CreateGEP(value, indices, "slice.ptr") slicePtr := c.builder.CreateGEP(value, indices, "slice.ptr")
sliceLen := c.builder.CreateSub(high, low, "slice.len") sliceLen := c.builder.CreateSub(high, low, "slice.len")
sliceCap := c.builder.CreateSub(llvmLen, low, "slice.cap") sliceCap := c.builder.CreateSub(llvmLenInt, low, "slice.cap")
// This check is optimized away in most cases. // This check is optimized away in most cases.
if !frame.fn.nobounds { if !frame.fn.nobounds {
@ -2334,6 +2350,11 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
c.builder.CreateCall(sliceBoundsCheck, []llvm.Value{llvmLen, low, high}, "") c.builder.CreateCall(sliceBoundsCheck, []llvm.Value{llvmLen, low, high}, "")
} }
if c.targetData.TypeAllocSize(sliceLen.Type()) > c.targetData.TypeAllocSize(c.lenType) {
sliceLen = c.builder.CreateTrunc(sliceLen, c.lenType, "")
sliceCap = c.builder.CreateTrunc(sliceCap, c.lenType, "")
}
slice := llvm.ConstStruct([]llvm.Value{ slice := llvm.ConstStruct([]llvm.Value{
llvm.Undef(slicePtr.Type()), llvm.Undef(slicePtr.Type()),
llvm.Undef(c.lenType), llvm.Undef(c.lenType),
@ -2358,6 +2379,13 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
c.builder.CreateCall(sliceBoundsCheck, []llvm.Value{oldLen, low, high}, "") c.builder.CreateCall(sliceBoundsCheck, []llvm.Value{oldLen, low, high}, "")
} }
if c.targetData.TypeAllocSize(low.Type()) > c.targetData.TypeAllocSize(c.lenType) {
low = c.builder.CreateTrunc(low, c.lenType, "")
}
if c.targetData.TypeAllocSize(high.Type()) > c.targetData.TypeAllocSize(c.lenType) {
high = c.builder.CreateTrunc(high, c.lenType, "")
}
newPtr := c.builder.CreateGEP(oldPtr, []llvm.Value{low}, "") newPtr := c.builder.CreateGEP(oldPtr, []llvm.Value{low}, "")
newLen := c.builder.CreateSub(high, low, "") newLen := c.builder.CreateSub(high, low, "")
newCap := c.builder.CreateSub(oldCap, low, "") newCap := c.builder.CreateSub(oldCap, low, "")

11
src/runtime/arch_avr.go Обычный файл
Просмотреть файл

@ -0,0 +1,11 @@
// +build avr
package runtime
const GOARCH = "avr"
// The length type used inside strings and slices.
type lenType uint16
// The bitness of the CPU (e.g. 8, 32, 64).
const TargetBits = 8

Просмотреть файл

@ -1,4 +1,4 @@
// +build wasm // +build wasm,!avr
package runtime package runtime

Просмотреть файл

@ -16,15 +16,15 @@ func runtimePanic(msg string) {
} }
// Check for bounds in *ssa.Index, *ssa.IndexAddr and *ssa.Lookup. // Check for bounds in *ssa.Index, *ssa.IndexAddr and *ssa.Lookup.
func lookupBoundsCheck(length, index int) { func lookupBoundsCheck(length lenType, index int) {
if index < 0 || index >= length { if index < 0 || index >= int(length) {
runtimePanic("index out of range") runtimePanic("index out of range")
} }
} }
// Check for bounds in *ssa.Slice. // Check for bounds in *ssa.Slice.
func sliceBoundsCheck(length, low, high uint) { func sliceBoundsCheck(length lenType, low, high uint) {
if !(0 <= low && low <= high && high <= length) { if !(0 <= low && low <= high && high <= uint(length)) {
runtimePanic("slice out of range") runtimePanic("slice out of range")
} }
} }