Example #1
0
// 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, "")
}
Example #2
0
func primitiveTypeToLLVMType(typ parser.PrimitiveType) llvm.Type {
	switch typ {
	case parser.PRIMITIVE_int, parser.PRIMITIVE_uint:
		return llvm.IntType(intSize * 8)
	case parser.PRIMITIVE_s8, parser.PRIMITIVE_u8:
		return llvm.IntType(8)
	case parser.PRIMITIVE_s16, parser.PRIMITIVE_u16:
		return llvm.IntType(16)
	case parser.PRIMITIVE_s32, parser.PRIMITIVE_u32:
		return llvm.IntType(32)
	case parser.PRIMITIVE_s64, parser.PRIMITIVE_u64:
		return llvm.IntType(64)
	case parser.PRIMITIVE_i128, parser.PRIMITIVE_u128:
		return llvm.IntType(128)

	case parser.PRIMITIVE_f32:
		return llvm.FloatType()
	case parser.PRIMITIVE_f64:
		return llvm.DoubleType()
	case parser.PRIMITIVE_f128:
		return llvm.FP128Type()

	case parser.PRIMITIVE_rune: // runes are signed 32-bit int
		return llvm.IntType(32)
	case parser.PRIMITIVE_bool:
		return llvm.IntType(1)
	case parser.PRIMITIVE_str:
		return llvm.PointerType(llvm.IntType(8), 0)

	default:
		panic("Unimplemented primitive type in LLVM codegen")
	}
}
Example #3
0
File: type.go Project: vnev/ark
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))}
}
Example #4
0
// 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)
	}
}
Example #5
0
File: codegen.go Project: vnev/ark
func (v *Codegen) genLogicalBinop(n *parser.BinaryExpr) llvm.Value {
	and := n.Op == parser.BINOP_LOG_AND

	next := llvm.AddBasicBlock(v.currentLLVMFunction(), "and_next")
	exit := llvm.AddBasicBlock(v.currentLLVMFunction(), "and_exit")

	b1 := v.genExpr(n.Lhand)
	first := v.builder().GetInsertBlock()
	if and {
		v.builder().CreateCondBr(b1, next, exit)
	} else {
		v.builder().CreateCondBr(b1, exit, next)
	}

	v.builder().SetInsertPointAtEnd(next)
	b2 := v.genExpr(n.Rhand)
	next = v.builder().GetInsertBlock()
	v.builder().CreateBr(exit)

	v.builder().SetInsertPointAtEnd(exit)
	phi := v.builder().CreatePHI(b2.Type(), "and_phi")

	var testIncVal uint64
	if and {
		testIncVal = 0
	} else {
		testIncVal = 1
	}

	phi.AddIncoming([]llvm.Value{llvm.ConstInt(llvm.IntType(1), testIncVal, false), b2}, []llvm.BasicBlock{first, next})

	return phi
}
Example #6
0
File: type.go Project: vnev/ark
func (v *Codegen) enumTypeToLLVMType(typ parser.EnumType) llvm.Type {
	if typ.Simple {
		// TODO: Handle other integer size, maybe dynamic depending on max value? (1 / 2)
		return llvm.IntType(32)
	}

	return llvm.StructType(v.enumTypeToLLVMTypeFields(typ), false)
}
Example #7
0
File: type.go Project: vnev/ark
func (v *Codegen) primitiveTypeToLLVMType(typ parser.PrimitiveType) llvm.Type {
	switch typ {
	case parser.PRIMITIVE_int, parser.PRIMITIVE_uint:
		return v.targetData.IntPtrType()

	case parser.PRIMITIVE_s8, parser.PRIMITIVE_u8:
		return llvm.IntType(8)
	case parser.PRIMITIVE_s16, parser.PRIMITIVE_u16:
		return llvm.IntType(16)
	case parser.PRIMITIVE_s32, parser.PRIMITIVE_u32:
		return llvm.IntType(32)
	case parser.PRIMITIVE_s64, parser.PRIMITIVE_u64:
		return llvm.IntType(64)
	case parser.PRIMITIVE_s128, parser.PRIMITIVE_u128:
		return llvm.IntType(128)

	case parser.PRIMITIVE_f32:
		return llvm.FloatType()
	case parser.PRIMITIVE_f64:
		return llvm.DoubleType()
	case parser.PRIMITIVE_f128:
		return llvm.FP128Type()

	case parser.PRIMITIVE_rune: // runes are signed 32-bit int
		return llvm.IntType(32)
	case parser.PRIMITIVE_bool:
		return llvm.IntType(1)
	case parser.PRIMITIVE_void:
		return llvm.VoidType()

	default:
		panic("Unimplemented primitive type in LLVM codegen")
	}
}
Example #8
0
File: codegen.go Project: vnev/ark
func (v *Codegen) genArrayLenExpr(n *parser.ArrayLenExpr) llvm.Value {
	if arrayLit, ok := n.Expr.(*parser.CompositeLiteral); ok {
		arrayLen := len(arrayLit.Values)

		return llvm.ConstInt(llvm.IntType(64), uint64(arrayLen), false)
	}

	gep := v.genAccessGEP(n.Expr)
	gep = v.builder().CreateLoad(v.builder().CreateStructGEP(gep, 0, ""), "")
	return gep
}
Example #9
0
func (v *Codegen) enumTypeToLLVMType(typ *parser.EnumType) llvm.Type {
	if typ.Simple {
		// TODO: Handle other integer size, maybe dynamic depending on max value? (1 / 2)
		return llvm.IntType(32)
	}

	if t, ok := v.enumLookup_UseHelperFunction[typ]; ok {
		return t
	}

	return llvm.StructType(v.enumTypeToLLVMTypeFields(typ), false)
}
Example #10
0
File: codegen.go Project: vnev/ark
func (v *Codegen) genEnumLiteral(n *parser.EnumLiteral) llvm.Value {
	enumType := n.Type.ActualType().(parser.EnumType)
	enumLLVMType := v.typeToLLVMType(n.Type)

	memberIdx := enumType.MemberIndex(n.Member)
	member := enumType.Members[memberIdx]

	if enumType.Simple {
		return llvm.ConstInt(enumLLVMType, uint64(member.Tag), false)
	}

	// TODO: Handle other integer size, maybe dynamic depending on max value?
	tagValue := llvm.ConstInt(llvm.IntType(32), uint64(member.Tag), false)

	enumValue := llvm.Undef(enumLLVMType)
	enumValue = v.builder().CreateInsertValue(enumValue, tagValue, 0, "")

	memberLLVMType := v.typeToLLVMType(member.Type)

	var memberValue llvm.Value
	if n.TupleLiteral != nil {
		memberValue = v.genTupleLiteral(n.TupleLiteral)
	} else if n.CompositeLiteral != nil {
		memberValue = v.genCompositeLiteral(n.CompositeLiteral)
	}

	if v.inFunction() {
		alloc := v.builder().CreateAlloca(enumLLVMType, "")

		tagGep := v.builder().CreateStructGEP(alloc, 0, "")
		v.builder().CreateStore(tagValue, tagGep)

		if !memberValue.IsNil() {
			dataGep := v.builder().CreateStructGEP(alloc, 1, "")

			dataGep = v.builder().CreateBitCast(dataGep, llvm.PointerType(memberLLVMType, 0), "")

			v.builder().CreateStore(memberValue, dataGep)
		}

		return v.builder().CreateLoad(alloc, "")
	} else {
		panic("unimplemented: global enum literal")
	}
}
Example #11
0
// 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)

	arrayValues := make([]llvm.Value, len(n.Members))
	for idx, mem := range n.Members {
		value := v.genExpr(mem)
		if !v.inFunction && !value.IsConstant() {
			v.err("Encountered non-constant value in global array")
		}
		arrayValues[idx] = value
	}

	lengthValue := llvm.ConstInt(llvm.IntType(32), uint64(len(n.Members)), false)
	var backingArrayPointer llvm.Value

	if v.inFunction {
		// allocate backing array
		backingArray := v.builder.CreateAlloca(llvm.ArrayType(memberLLVMType, len(n.Members)), "")

		// 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(llvm.ArrayType(memberLLVMType, 0), 0), "")
	} else {
		backName := fmt.Sprintf("_globarr_back_%d", v.arrayIndex)
		v.arrayIndex++

		backingArray := llvm.AddGlobal(v.curFile.Module, llvm.ArrayType(memberLLVMType, len(n.Members)), backName)
		backingArray.SetLinkage(llvm.InternalLinkage)
		backingArray.SetGlobalConstant(false)
		backingArray.SetInitializer(llvm.ConstArray(memberLLVMType, arrayValues))

		backingArrayPointer = llvm.ConstBitCast(backingArray, llvm.PointerType(llvm.ArrayType(memberLLVMType, 0), 0))
	}

	structValue := llvm.Undef(arrayLLVMType)
	structValue = v.builder.CreateInsertValue(structValue, lengthValue, 0, "")
	structValue = v.builder.CreateInsertValue(structValue, backingArrayPointer, 1, "")
	return structValue
}
Example #12
0
File: codegen.go Project: vnev/ark
func (v *Codegen) addEnumType(typ parser.EnumType, name string) {
	if _, ok := v.namedTypeLookup[name]; ok {
		return
	}

	if typ.Simple {
		// TODO: Handle other integer size, maybe dynamic depending on max value?
		v.namedTypeLookup[name] = llvm.IntType(32)
	} else {
		enum := v.curFile.LlvmModule.Context().StructCreateNamed(name)
		v.namedTypeLookup[name] = enum

		for _, member := range typ.Members {
			if named, ok := member.Type.(*parser.NamedType); ok {
				v.addNamedType(named)
			}
		}

		enum.StructSetBody(v.enumTypeToLLVMTypeFields(typ), false)
	}
}
Example #13
0
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)
}
Example #14
0
func (v *Codegen) genVariableDecl(n *parser.VariableDecl, semicolon bool) llvm.Value {
	var res llvm.Value

	if v.inFunction {
		mangledName := n.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE)

		funcEntry := v.currentFunction.EntryBasicBlock()

		// use this builder for the variable alloca
		// this means all allocas go at the start of the function
		// so each variable is only allocated once
		allocBuilder := llvm.NewBuilder()

		if funcEntry == v.builder.GetInsertBlock() {
			allocBuilder.SetInsertPointAtEnd(funcEntry)
		} else {
			allocBuilder.SetInsertPointBefore(funcEntry.LastInstruction())
		}

		alloc := allocBuilder.CreateAlloca(v.typeToLLVMType(n.Variable.Type), mangledName)

		// set allocated memory to zero
		fn := v.curFile.Module.NamedFunction("llvm.memset.p0i8.i32")
		if fn.IsNil() {
			fnType := llvm.FunctionType(llvm.VoidType(), []llvm.Type{llvm.PointerType(llvm.IntType(8), 0), llvm.IntType(8), llvm.IntType(32), llvm.IntType(32), llvm.IntType(1)}, false)
			fn = llvm.AddFunction(v.curFile.Module, "llvm.memset.p0i8.i32", fnType)
		}

		// cast alloc to byte array
		castAlloc := allocBuilder.CreateBitCast(alloc, llvm.PointerType(llvm.IntType(8), 0), "")

		// get type length
		gep := allocBuilder.CreateGEP(llvm.ConstNull(llvm.PointerType(v.typeToLLVMType(n.Variable.Type), 0)), []llvm.Value{llvm.ConstInt(llvm.IntType(32), 1, false)}, "")
		length := allocBuilder.CreatePtrToInt(gep, llvm.IntType(32), "")

		// call memset intrinsic
		allocBuilder.CreateCall(fn, []llvm.Value{castAlloc, llvm.ConstInt(llvm.IntType(8), 0, false), length, llvm.ConstInt(llvm.IntType(32), 0, false), llvm.ConstInt(llvm.IntType(1), 0, false)}, "")

		allocBuilder.Dispose()

		v.variableLookup[n.Variable] = alloc

		if n.Assignment != nil {
			if value := v.genExpr(n.Assignment); !value.IsNil() {
				v.builder.CreateStore(value, alloc)
			}
		}
	} else {
		mangledName := n.Variable.MangledName(parser.MANGLE_ARK_UNSTABLE)
		varType := v.typeToLLVMType(n.Variable.Type)
		value := llvm.AddGlobal(v.curFile.Module, varType, mangledName)
		value.SetLinkage(llvm.InternalLinkage)
		value.SetGlobalConstant(!n.Variable.Mutable)
		if n.Assignment != nil {
			value.SetInitializer(v.genExpr(n.Assignment))
		}
		v.variableLookup[n.Variable] = value
	}

	return res
}
Example #15
0
func (v *Codegen) genSizeofExpr(n *parser.SizeofExpr) llvm.Value {
	if n.Expr != nil {
		gep := v.builder.CreateGEP(llvm.ConstNull(llvm.PointerType(v.typeToLLVMType(n.Expr.GetType()), 0)), []llvm.Value{llvm.ConstInt(llvm.IntType(32), 1, false)}, "")
		return v.builder.CreatePtrToInt(gep, v.typeToLLVMType(n.GetType()), "sizeof")
	} else {
		// we have a type
		panic("can't do this yet")
	}
}