1//===- slice.go - IR generation for slices --------------------------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file implements IR generation for slices. 10// 11//===----------------------------------------------------------------------===// 12 13package irgen 14 15import ( 16 "llvm.org/llgo/third_party/gotools/go/types" 17 "llvm.org/llvm/bindings/go/llvm" 18) 19 20// makeSlice allocates a new slice with the optional length and capacity, 21// initialising its contents to their zero values. 22func (fr *frame) makeSlice(sliceType types.Type, length, capacity *govalue) *govalue { 23 length = fr.convert(length, types.Typ[types.Uintptr]) 24 capacity = fr.convert(capacity, types.Typ[types.Uintptr]) 25 runtimeType := fr.types.ToRuntime(sliceType) 26 llslice := fr.runtime.makeSlice.call(fr, runtimeType, length.value, capacity.value) 27 return newValue(llslice[0], sliceType) 28} 29 30func (fr *frame) slice(x llvm.Value, xtyp types.Type, low, high, max llvm.Value) llvm.Value { 31 if !low.IsNil() { 32 low = fr.createZExtOrTrunc(low, fr.types.inttype, "") 33 } else { 34 low = llvm.ConstNull(fr.types.inttype) 35 } 36 if !high.IsNil() { 37 high = fr.createZExtOrTrunc(high, fr.types.inttype, "") 38 } 39 if !max.IsNil() { 40 max = fr.createZExtOrTrunc(max, fr.types.inttype, "") 41 } 42 43 var arrayptr, arraylen, arraycap llvm.Value 44 var elemtyp types.Type 45 var errcode uint64 46 switch typ := xtyp.Underlying().(type) { 47 case *types.Pointer: // *array 48 errcode = gccgoRuntimeErrorARRAY_SLICE_OUT_OF_BOUNDS 49 arraytyp := typ.Elem().Underlying().(*types.Array) 50 elemtyp = arraytyp.Elem() 51 arrayptr = x 52 arrayptr = fr.builder.CreateBitCast(arrayptr, llvm.PointerType(llvm.Int8Type(), 0), "") 53 arraylen = llvm.ConstInt(fr.llvmtypes.inttype, uint64(arraytyp.Len()), false) 54 arraycap = arraylen 55 case *types.Slice: 56 errcode = gccgoRuntimeErrorSLICE_SLICE_OUT_OF_BOUNDS 57 elemtyp = typ.Elem() 58 arrayptr = fr.builder.CreateExtractValue(x, 0, "") 59 arraylen = fr.builder.CreateExtractValue(x, 1, "") 60 arraycap = fr.builder.CreateExtractValue(x, 2, "") 61 case *types.Basic: 62 if high.IsNil() { 63 high = llvm.ConstAllOnes(fr.types.inttype) // -1 64 } 65 result := fr.runtime.stringSlice.call(fr, x, low, high) 66 return result[0] 67 default: 68 panic("unimplemented") 69 } 70 if high.IsNil() { 71 high = arraylen 72 } 73 if max.IsNil() { 74 max = arraycap 75 } 76 77 // Bounds checking: 0 <= low <= high <= max <= cap 78 zero := llvm.ConstNull(fr.types.inttype) 79 l0 := fr.builder.CreateICmp(llvm.IntSLT, low, zero, "") 80 hl := fr.builder.CreateICmp(llvm.IntSLT, high, low, "") 81 mh := fr.builder.CreateICmp(llvm.IntSLT, max, high, "") 82 cm := fr.builder.CreateICmp(llvm.IntSLT, arraycap, max, "") 83 84 cond := fr.builder.CreateOr(l0, hl, "") 85 cond = fr.builder.CreateOr(cond, mh, "") 86 cond = fr.builder.CreateOr(cond, cm, "") 87 88 fr.condBrRuntimeError(cond, errcode) 89 90 slicelen := fr.builder.CreateSub(high, low, "") 91 slicecap := fr.builder.CreateSub(max, low, "") 92 93 elemsize := llvm.ConstInt(fr.llvmtypes.inttype, uint64(fr.llvmtypes.Sizeof(elemtyp)), false) 94 offset := fr.builder.CreateMul(low, elemsize, "") 95 96 sliceptr := fr.builder.CreateInBoundsGEP(arrayptr, []llvm.Value{offset}, "") 97 98 llslicetyp := fr.llvmtypes.sliceBackendType().ToLLVM(fr.llvmtypes.ctx) 99 sliceValue := llvm.Undef(llslicetyp) 100 sliceValue = fr.builder.CreateInsertValue(sliceValue, sliceptr, 0, "") 101 sliceValue = fr.builder.CreateInsertValue(sliceValue, slicelen, 1, "") 102 sliceValue = fr.builder.CreateInsertValue(sliceValue, slicecap, 2, "") 103 104 return sliceValue 105} 106