diff --git a/compiler.go b/compiler.go index 334bfe7f..ade0b9bd 100644 --- a/compiler.go +++ b/compiler.go @@ -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. c.intType = llvm.Int32Type() - c.lenType = llvm.Int32Type() // also defined as runtime.lenType 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) 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 { return llvm.Value{}, err } + var llvmLen llvm.Value switch args[0].Type().(type) { case *types.Basic, *types.Slice: // string or slice - return c.builder.CreateExtractValue(value, 1, "len"), nil + llvmLen = c.builder.CreateExtractValue(value, 1, "len") case *types.Map: indices := []llvm.Value{ llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), 2, false), // hashmap.count } ptr := c.builder.CreateGEP(value, indices, "lenptr") - return c.builder.CreateLoad(ptr, "len"), nil + llvmLen = c.builder.CreateLoad(ptr, "len") default: 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": for i, arg := range args { if i >= 1 && callName == "println" { @@ -2041,7 +2051,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { // Check bounds. 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) // 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) { case *types.Array: bufptr = val - buflen = llvm.ConstInt(llvm.Int32Type(), uint64(typ.Len()), false) + buflen = llvm.ConstInt(c.lenType, uint64(typ.Len()), false) default: 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.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. slice := llvm.ConstStruct([]llvm.Value{ 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 if expr.Low == nil { - low = llvm.ConstInt(c.lenType, 0, false) + low = llvm.ConstInt(c.intType, 0, false) } else { low, err = c.parseExpr(frame, expr.Low) if err != nil { @@ -2317,8 +2332,9 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { // slice an array length := typ.Elem().(*types.Array).Len() llvmLen := llvm.ConstInt(c.lenType, uint64(length), false) + llvmLenInt := llvm.ConstInt(c.intType, uint64(length), false) if high.IsNil() { - high = llvmLen + high = llvmLenInt } indices := []llvm.Value{ 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") 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. 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}, "") } + 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{ llvm.Undef(slicePtr.Type()), 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}, "") } + 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}, "") newLen := c.builder.CreateSub(high, low, "") newCap := c.builder.CreateSub(oldCap, low, "") diff --git a/src/runtime/arch_avr.go b/src/runtime/arch_avr.go new file mode 100644 index 00000000..2c92967e --- /dev/null +++ b/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 diff --git a/src/runtime/arch_wasm.go b/src/runtime/arch_wasm.go index 4918df6a..65af4370 100644 --- a/src/runtime/arch_wasm.go +++ b/src/runtime/arch_wasm.go @@ -1,4 +1,4 @@ -// +build wasm +// +build wasm,!avr package runtime diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 12a13996..6cbef364 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -16,15 +16,15 @@ func runtimePanic(msg string) { } // Check for bounds in *ssa.Index, *ssa.IndexAddr and *ssa.Lookup. -func lookupBoundsCheck(length, index int) { - if index < 0 || index >= length { +func lookupBoundsCheck(length lenType, index int) { + if index < 0 || index >= int(length) { runtimePanic("index out of range") } } // Check for bounds in *ssa.Slice. -func sliceBoundsCheck(length, low, high uint) { - if !(0 <= low && low <= high && high <= length) { +func sliceBoundsCheck(length lenType, low, high uint) { + if !(0 <= low && low <= high && high <= uint(length)) { runtimePanic("slice out of range") } }