// Allocates a literal array on the stack func (v *Codegen) genArrayLiteral(n *parser.ArrayLiteral) llvm.Value { memberLLVMType := v.typeToLLVMType(n.Type.(parser.ArrayType).MemberType) // allocate backing array arrAlloca := v.builder.CreateArrayAlloca(llvm.ArrayType(memberLLVMType, len(n.Members)), llvm.ConstInt(llvm.IntType(32), uint64(len(n.Members)), false), "") // allocate the array object structAlloca := v.builder.CreateAlloca(v.typeToLLVMType(n.Type), "") // set the length of the array lenGEP := v.builder.CreateGEP(structAlloca, []llvm.Value{llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(32), 0, false)}, "") v.builder.CreateStore(llvm.ConstInt(llvm.IntType(32), uint64(len(n.Members)), false), lenGEP) // set the array pointer to the backing array we allocated arrGEP := v.builder.CreateGEP(structAlloca, []llvm.Value{llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(32), 1, false)}, "") v.builder.CreateStore(v.builder.CreateBitCast(arrAlloca, llvm.PointerType(llvm.ArrayType(memberLLVMType, 0), 0), ""), arrGEP) // copy the constant array to the backing array arrConstVals := make([]llvm.Value, 0, len(n.Members)) for _, mem := range n.Members { arrConstVals = append(arrConstVals, v.genExpr(mem)) } arrConst := llvm.ConstArray(llvm.ArrayType(memberLLVMType, len(n.Members)), arrConstVals) v.builder.CreateStore(arrConst, arrAlloca) return v.builder.CreateLoad(structAlloca, "") }
// Allocates a literal array on the stack func (v *Codegen) genArrayLiteral(n *parser.ArrayLiteral) llvm.Value { arrayLLVMType := v.typeToLLVMType(n.Type) memberLLVMType := v.typeToLLVMType(n.Type.(parser.ArrayType).MemberType) if v.inFunction { // allocate backing array arrAlloca := v.builder.CreateAlloca(llvm.ArrayType(memberLLVMType, len(n.Members)), "") // copy the constant array to the backing array for idx, value := range n.Members { gep := v.builder.CreateGEP(arrAlloca, []llvm.Value{llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(32), uint64(idx), false)}, "") value := v.genExpr(value) v.builder.CreateStore(value, gep) } // allocate struct structAlloca := v.builder.CreateAlloca(arrayLLVMType, "") // set the length of the array lenGEP := v.builder.CreateGEP(structAlloca, []llvm.Value{llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(32), 0, false)}, "") v.builder.CreateStore(llvm.ConstInt(llvm.IntType(32), uint64(len(n.Members)), false), lenGEP) // set the array pointer to the backing array we allocated arrGEP := v.builder.CreateGEP(structAlloca, []llvm.Value{llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(32), 1, false)}, "") v.builder.CreateStore(v.builder.CreateBitCast(arrAlloca, llvm.PointerType(llvm.ArrayType(memberLLVMType, 0), 0), ""), arrGEP) return v.builder.CreateLoad(structAlloca, "") } else { backName := fmt.Sprintf("_globarr_back_%d", v.arrayIndex) v.arrayIndex++ backGlob := llvm.AddGlobal(v.curFile.Module, llvm.ArrayType(memberLLVMType, len(n.Members)), backName) backGlob.SetLinkage(llvm.InternalLinkage) backGlob.SetGlobalConstant(false) arrConstVals := make([]llvm.Value, len(n.Members)) for idx, mem := range n.Members { value := v.genExpr(mem) if !value.IsConstant() { v.err("Encountered non-constant value in global array") } arrConstVals[idx] = v.genExpr(mem) } backGlob.SetInitializer(llvm.ConstArray(memberLLVMType, arrConstVals)) lengthVal := llvm.ConstInt(llvm.IntType(32), uint64(len(n.Members)), false) backRef := llvm.ConstBitCast(backGlob, llvm.PointerType(llvm.ArrayType(memberLLVMType, 0), 0)) return llvm.ConstStruct([]llvm.Value{lengthVal, backRef}, false) } }
// Allocates a literal array on the stack func (v *Codegen) genArrayLiteral(n *parser.CompositeLiteral) llvm.Value { arrayLLVMType := v.typeToLLVMType(n.Type) memberLLVMType := v.typeToLLVMType(n.Type.ActualType().(parser.ArrayType).MemberType) arrayValues := make([]llvm.Value, len(n.Values)) for idx, mem := range n.Values { value := v.genExpr(mem) if !v.inFunction() && !value.IsConstant() { v.err("Encountered non-constant value in global array") } arrayValues[idx] = value } lengthValue := llvm.ConstInt(v.typeToLLVMType(parser.PRIMITIVE_uint), uint64(len(n.Values)), false) var backingArrayPointer llvm.Value if v.inFunction() { // allocate backing array backingArray := v.builder().CreateAlloca(llvm.ArrayType(memberLLVMType, len(n.Values)), "") // copy the constant array to the backing array for idx, value := range arrayValues { gep := v.builder().CreateStructGEP(backingArray, idx, "") v.builder().CreateStore(value, gep) } backingArrayPointer = v.builder().CreateBitCast(backingArray, llvm.PointerType(memberLLVMType, 0), "") } else { backName := fmt.Sprintf("_globarr_back_%d", v.arrayIndex) v.arrayIndex++ backingArray := llvm.AddGlobal(v.curFile.LlvmModule, llvm.ArrayType(memberLLVMType, len(n.Values)), backName) backingArray.SetLinkage(llvm.InternalLinkage) backingArray.SetGlobalConstant(false) backingArray.SetInitializer(llvm.ConstArray(memberLLVMType, arrayValues)) backingArrayPointer = llvm.ConstBitCast(backingArray, llvm.PointerType(memberLLVMType, 0)) } structValue := llvm.Undef(arrayLLVMType) structValue = v.builder().CreateInsertValue(structValue, lengthValue, 0, "") structValue = v.builder().CreateInsertValue(structValue, backingArrayPointer, 1, "") return structValue }
func (v *Codegen) enumTypeToLLVMTypeFields(typ parser.EnumType) []llvm.Type { longestLength := uint64(0) for _, member := range typ.Members { memLength := v.targetData.TypeAllocSize(v.typeToLLVMType(member.Type)) if memLength > longestLength { longestLength = memLength } } // TODO: verify no overflow return []llvm.Type{llvm.IntType(32), llvm.ArrayType(llvm.IntType(8), int(longestLength))} }
func (v *Codegen) genStringLiteral(n *parser.StringLiteral) llvm.Value { memberLLVMType := v.typeToLLVMType(parser.PRIMITIVE_u8) nullTerm := n.IsCString length := len(n.Value) if nullTerm { length++ } var backingArrayPointer llvm.Value if v.inFunction() { // allocate backing array backingArray := v.builder().CreateAlloca(llvm.ArrayType(memberLLVMType, length), "stackstr") v.builder().CreateStore(llvm.ConstString(n.Value, nullTerm), backingArray) backingArrayPointer = v.builder().CreateBitCast(backingArray, llvm.PointerType(memberLLVMType, 0), "") } else { backName := fmt.Sprintf("_globarr_back_%d", v.arrayIndex) v.arrayIndex++ backingArray := llvm.AddGlobal(v.curFile.LlvmModule, llvm.ArrayType(memberLLVMType, length), backName) backingArray.SetLinkage(llvm.InternalLinkage) backingArray.SetGlobalConstant(false) backingArray.SetInitializer(llvm.ConstString(n.Value, nullTerm)) backingArrayPointer = llvm.ConstBitCast(backingArray, llvm.PointerType(memberLLVMType, 0)) } if n.Type.ActualType().Equals(parser.ArrayOf(parser.PRIMITIVE_u8)) { lengthValue := llvm.ConstInt(v.typeToLLVMType(parser.PRIMITIVE_uint), uint64(length), false) structValue := llvm.Undef(v.typeToLLVMType(n.Type)) structValue = v.builder().CreateInsertValue(structValue, lengthValue, 0, "") structValue = v.builder().CreateInsertValue(structValue, backingArrayPointer, 1, "") return structValue } else { return backingArrayPointer } }
func (t arrayBType) ToLLVM(c llvm.Context) llvm.Type { return llvm.ArrayType(t.elem.ToLLVM(c), int(t.length)) }
func (v *Codegen) arrayTypeToLLVMType(typ parser.ArrayType) llvm.Type { fields := []llvm.Type{llvm.IntType(32), llvm.PointerType(llvm.ArrayType(v.typeToLLVMType(typ.MemberType), 0), 0)} return llvm.StructType(fields, false) }
// mapIterNext advances the iterator, and returns the tuple (ok, k, v). func (fr *frame) mapIterNext(iter []*govalue) []*govalue { maptyp := iter[0].Type().Underlying().(*types.Map) ktyp := maptyp.Key() klltyp := fr.types.ToLLVM(ktyp) vtyp := maptyp.Elem() vlltyp := fr.types.ToLLVM(vtyp) m, isinitptr := iter[0], iter[1] i8ptr := llvm.PointerType(llvm.Int8Type(), 0) mapiterbufty := llvm.ArrayType(i8ptr, 4) mapiterbuf := fr.allocaBuilder.CreateAlloca(mapiterbufty, "") mapiterbufelem0ptr := fr.builder.CreateStructGEP(mapiterbuf, 0, "") keybuf := fr.allocaBuilder.CreateAlloca(klltyp, "") keyptr := fr.builder.CreateBitCast(keybuf, i8ptr, "") valbuf := fr.allocaBuilder.CreateAlloca(vlltyp, "") valptr := fr.builder.CreateBitCast(valbuf, i8ptr, "") isinit := fr.builder.CreateLoad(isinitptr.value, "") initbb := llvm.AddBasicBlock(fr.function, "") nextbb := llvm.AddBasicBlock(fr.function, "") contbb := llvm.AddBasicBlock(fr.function, "") fr.builder.CreateCondBr(isinit, nextbb, initbb) fr.builder.SetInsertPointAtEnd(initbb) fr.builder.CreateStore(llvm.ConstAllOnes(llvm.Int1Type()), isinitptr.value) fr.runtime.mapiterinit.call(fr, m.value, mapiterbufelem0ptr) fr.builder.CreateBr(contbb) fr.builder.SetInsertPointAtEnd(nextbb) fr.runtime.mapiternext.call(fr, mapiterbufelem0ptr) fr.builder.CreateBr(contbb) fr.builder.SetInsertPointAtEnd(contbb) mapiterbufelem0 := fr.builder.CreateLoad(mapiterbufelem0ptr, "") okbit := fr.builder.CreateIsNotNull(mapiterbufelem0, "") ok := fr.builder.CreateZExt(okbit, llvm.Int8Type(), "") loadbb := llvm.AddBasicBlock(fr.function, "") cont2bb := llvm.AddBasicBlock(fr.function, "") fr.builder.CreateCondBr(okbit, loadbb, cont2bb) fr.builder.SetInsertPointAtEnd(loadbb) fr.runtime.mapiter2.call(fr, mapiterbufelem0ptr, keyptr, valptr) loadbb = fr.builder.GetInsertBlock() loadedkey := fr.builder.CreateLoad(keybuf, "") loadedval := fr.builder.CreateLoad(valbuf, "") fr.builder.CreateBr(cont2bb) fr.builder.SetInsertPointAtEnd(cont2bb) k := fr.builder.CreatePHI(klltyp, "") k.AddIncoming( []llvm.Value{llvm.ConstNull(klltyp), loadedkey}, []llvm.BasicBlock{contbb, loadbb}, ) v := fr.builder.CreatePHI(vlltyp, "") v.AddIncoming( []llvm.Value{llvm.ConstNull(vlltyp), loadedval}, []llvm.BasicBlock{contbb, loadbb}, ) return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, ktyp), newValue(v, vtyp)} }