diff --git a/compiler.go b/compiler.go index a4c9c2be..4036062a 100644 --- a/compiler.go +++ b/compiler.go @@ -2087,6 +2087,48 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { llvmValueSize := llvm.ConstInt(llvm.Int8Type(), valueSize, false) hashmap := c.builder.CreateCall(hashmapMake, []llvm.Value{llvmKeySize, llvmValueSize}, "") return hashmap, nil + case *ssa.MakeSlice: + sliceLen, err := c.parseExpr(frame, expr.Len) + if err != nil { + return llvm.Value{}, nil + } + sliceCap, err := c.parseExpr(frame, expr.Cap) + if err != nil { + return llvm.Value{}, nil + } + sliceType := expr.Type().Underlying().(*types.Slice) + llvmElemType, err := c.getLLVMType(sliceType.Elem()) + if err != nil { + return llvm.Value{}, nil + } + elemSize := c.targetData.TypeAllocSize(llvmElemType) + + // Bounds checking. + if !frame.fn.nobounds { + sliceBoundsCheck := c.mod.NamedFunction("runtime.sliceBoundsCheckMake") + c.builder.CreateCall(sliceBoundsCheck, []llvm.Value{sliceLen, sliceCap}, "") + } + + // Allocate the backing array. + // TODO: escape analysis + elemSizeValue := llvm.ConstInt(c.uintptrType, elemSize, false) + sliceCapCast, err := c.parseConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap) + if err != nil { + return llvm.Value{}, err + } + sliceSize := c.builder.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap") + slicePtr := c.builder.CreateCall(c.allocFunc, []llvm.Value{sliceSize}, "makeslice.buf") + + // Create the slice. + slice := llvm.ConstStruct([]llvm.Value{ + llvm.Undef(slicePtr.Type()), + llvm.Undef(c.lenType), + llvm.Undef(c.lenType), + }, false) + slice = c.builder.CreateInsertValue(slice, slicePtr, 0, "") + slice = c.builder.CreateInsertValue(slice, sliceLen, 1, "") + slice = c.builder.CreateInsertValue(slice, sliceCap, 2, "") + return slice, nil case *ssa.Phi: t, err := c.getLLVMType(expr.Type()) if err != nil { diff --git a/src/examples/test/test.go b/src/examples/test/test.go index 87143721..ec899559 100644 --- a/src/examples/test/test.go +++ b/src/examples/test/test.go @@ -35,8 +35,11 @@ func main() { readMap(testmap, "data") // slice + l := 5 foo := []int{1, 2, 4, 5} + bar := make([]byte, l-2, l) println("len/cap foo:", len(foo), cap(foo)) + println("len/cap bar:", len(bar), cap(bar)) println("foo[3]:", foo[3]) println("sum foo:", sum(foo)) diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go index 41af1b42..013fdf7c 100644 --- a/src/runtime/runtime.go +++ b/src/runtime/runtime.go @@ -99,10 +99,18 @@ func lookupBoundsCheck(length, index int) { } } -// Check for bounds in *ssa.Slice +// Check for bounds in *ssa.Slice. func sliceBoundsCheck(length, low, high uint) { if !(0 <= low && low <= high && high <= length) { printstring("panic: runtime error: slice out of range\n") abort() } } + +// Check for bounds in *ssa.MakeSlice. +func sliceBoundsCheckMake(length, capacity uint) { + if !(0 <= length && length <= capacity) { + printstring("panic: runtime error: slice size out of range\n") + abort() + } +}