//===- slice.go - IR generation for slices --------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements IR generation for slices. // //===----------------------------------------------------------------------===// package irgen import ( "llvm.org/llgo/third_party/gotools/go/types" "llvm.org/llvm/bindings/go/llvm" ) // makeSlice allocates a new slice with the optional length and capacity, // initialising its contents to their zero values. func (fr *frame) makeSlice(sliceType types.Type, length, capacity *govalue) *govalue { length = fr.convert(length, types.Typ[types.Uintptr]) capacity = fr.convert(capacity, types.Typ[types.Uintptr]) runtimeType := fr.types.ToRuntime(sliceType) llslice := fr.runtime.makeSlice.call(fr, runtimeType, length.value, capacity.value) return newValue(llslice[0], sliceType) } func (fr *frame) slice(x llvm.Value, xtyp types.Type, low, high, max llvm.Value) llvm.Value { if !low.IsNil() { low = fr.createZExtOrTrunc(low, fr.types.inttype, "") } else { low = llvm.ConstNull(fr.types.inttype) } if !high.IsNil() { high = fr.createZExtOrTrunc(high, fr.types.inttype, "") } if !max.IsNil() { max = fr.createZExtOrTrunc(max, fr.types.inttype, "") } var arrayptr, arraylen, arraycap llvm.Value var elemtyp types.Type var errcode uint64 switch typ := xtyp.Underlying().(type) { case *types.Pointer: // *array errcode = gccgoRuntimeErrorARRAY_SLICE_OUT_OF_BOUNDS arraytyp := typ.Elem().Underlying().(*types.Array) elemtyp = arraytyp.Elem() arrayptr = x arrayptr = fr.builder.CreateBitCast(arrayptr, llvm.PointerType(llvm.Int8Type(), 0), "") arraylen = llvm.ConstInt(fr.llvmtypes.inttype, uint64(arraytyp.Len()), false) arraycap = arraylen case *types.Slice: errcode = gccgoRuntimeErrorSLICE_SLICE_OUT_OF_BOUNDS elemtyp = typ.Elem() arrayptr = fr.builder.CreateExtractValue(x, 0, "") arraylen = fr.builder.CreateExtractValue(x, 1, "") arraycap = fr.builder.CreateExtractValue(x, 2, "") case *types.Basic: if high.IsNil() { high = llvm.ConstAllOnes(fr.types.inttype) // -1 } result := fr.runtime.stringSlice.call(fr, x, low, high) return result[0] default: panic("unimplemented") } if high.IsNil() { high = arraylen } if max.IsNil() { max = arraycap } // Bounds checking: 0 <= low <= high <= max <= cap zero := llvm.ConstNull(fr.types.inttype) l0 := fr.builder.CreateICmp(llvm.IntSLT, low, zero, "") hl := fr.builder.CreateICmp(llvm.IntSLT, high, low, "") mh := fr.builder.CreateICmp(llvm.IntSLT, max, high, "") cm := fr.builder.CreateICmp(llvm.IntSLT, arraycap, max, "") cond := fr.builder.CreateOr(l0, hl, "") cond = fr.builder.CreateOr(cond, mh, "") cond = fr.builder.CreateOr(cond, cm, "") fr.condBrRuntimeError(cond, errcode) slicelen := fr.builder.CreateSub(high, low, "") slicecap := fr.builder.CreateSub(max, low, "") elemsize := llvm.ConstInt(fr.llvmtypes.inttype, uint64(fr.llvmtypes.Sizeof(elemtyp)), false) offset := fr.builder.CreateMul(low, elemsize, "") sliceptr := fr.builder.CreateInBoundsGEP(arrayptr, []llvm.Value{offset}, "") llslicetyp := fr.llvmtypes.sliceBackendType().ToLLVM(fr.llvmtypes.ctx) sliceValue := llvm.Undef(llslicetyp) sliceValue = fr.builder.CreateInsertValue(sliceValue, sliceptr, 0, "") sliceValue = fr.builder.CreateInsertValue(sliceValue, slicelen, 1, "") sliceValue = fr.builder.CreateInsertValue(sliceValue, slicecap, 2, "") return sliceValue }