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