Esempio n. 1
0
File: codegen.go Progetto: vnev/ark
func (v *Codegen) genBoundsCheck(limit llvm.Value, index llvm.Value, indexType parser.Type) {
	segvBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_segv")
	endBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_end")
	upperCheckBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_upper_block")

	tooLow := v.builder().CreateICmp(llvm.IntSGT, llvm.ConstInt(index.Type(), 0, false), index, "boundscheck_lower")
	v.builder().CreateCondBr(tooLow, segvBlock, upperCheckBlock)

	v.builder().SetInsertPointAtEnd(upperCheckBlock)

	// make sure limit and index have same width
	castedLimit := limit
	castedIndex := index
	if index.Type().IntTypeWidth() < limit.Type().IntTypeWidth() {
		if indexType.IsSigned() {
			castedIndex = v.builder().CreateSExt(index, limit.Type(), "")
		} else {
			castedIndex = v.builder().CreateZExt(index, limit.Type(), "")
		}
	} else if index.Type().IntTypeWidth() > limit.Type().IntTypeWidth() {
		castedLimit = v.builder().CreateZExt(limit, index.Type(), "")
	}

	tooHigh := v.builder().CreateICmp(llvm.IntSLE, castedLimit, castedIndex, "boundscheck_upper")
	v.builder().CreateCondBr(tooHigh, segvBlock, endBlock)

	v.builder().SetInsertPointAtEnd(segvBlock)
	v.genRaiseSegfault()
	v.builder().CreateUnreachable()

	v.builder().SetInsertPointAtEnd(endBlock)
}
Esempio n. 2
0
func (v *RecursiveDefinitionCheck) Visit(s *SemanticAnalyzer, n parser.Node) {
	var typ parser.Type

	if typeDecl, ok := n.(*parser.TypeDecl); ok {
		actualType := typeDecl.NamedType.ActualType()
		switch actualType.(type) {
		case *parser.EnumType:
			typ = actualType.(*parser.EnumType)

		case *parser.StructType:
			typ = actualType.(*parser.StructType)

			// TODO: Check tuple types once we add named types for everything

		default:
			return
		}
	}

	if ok, path := isTypeRecursive(typ); ok {
		s.Err(n, "Encountered recursive type definition")

		log.Errorln("semantic", "Path taken:")
		for _, typ := range path {
			log.Error("semantic", typ.TypeName())
			log.Error("semantic", " <- ")
		}
		log.Error("semantic", "%s\n\n", typ.TypeName())
	}

}
Esempio n. 3
0
File: codegen.go Progetto: vnev/ark
func createStructInitializer(typ parser.Type) *parser.CompositeLiteral {
	lit := &parser.CompositeLiteral{Type: typ}
	hasDefaultValues := false

	structType := typ.ActualType().(parser.StructType)

	for _, decl := range structType.Variables {
		vari := decl.Variable

		var value parser.Expr
		if _, ok := vari.Type.ActualType().(parser.StructType); ok {
			value = createStructInitializer(vari.Type)
		} else {
			value = decl.Assignment
		}

		if value != nil {
			hasDefaultValues = true
			lit.Values = append(lit.Values, value)
			lit.Fields = append(lit.Fields, vari.Name)
		}
	}

	if hasDefaultValues {
		return lit
	}
	return nil
}
Esempio n. 4
0
File: codegen.go Progetto: vnev/ark
func (v *Codegen) genDefaultValue(typ parser.Type) llvm.Value {
	atyp := typ.ActualType()

	// Generate default struct values
	if structType, ok := atyp.(parser.StructType); ok {
		lit := createStructInitializer(typ)
		if lit != nil {
			return v.genStructLiteral(lit)
		} else {
			return llvm.Undef(v.typeToLLVMType(structType))
		}
	}

	if tupleType, ok := atyp.(parser.TupleType); ok {
		values := make([]llvm.Value, len(tupleType.Members))
		for idx, member := range tupleType.Members {
			values[idx] = v.genDefaultValue(member)
		}
		return llvm.ConstStruct(values, false)
	}

	if atyp.IsIntegerType() || atyp == parser.PRIMITIVE_bool {
		return llvm.ConstInt(v.typeToLLVMType(atyp), 0, false)
	}

	if atyp.IsFloatingType() {
		return llvm.ConstFloat(v.typeToLLVMType(atyp), 0)
	}

	panic("type does not have default value: " + atyp.TypeName())
}
Esempio n. 5
0
func createStructInitializer(typ parser.Type) *parser.StructLiteral {
	lit := &parser.StructLiteral{Type: typ, Values: make(map[string]parser.Expr)}
	hasDefaultValues := false

	structType := typ.ActualType().(parser.StructType)

	for _, decl := range structType.Variables {
		vari := decl.Variable

		var value parser.Expr
		if _, ok := vari.Type.ActualType().(parser.StructType); ok {
			value = createStructInitializer(vari.Type)
		} else {
			value = decl.Assignment
		}

		if value != nil {
			hasDefaultValues = true
			lit.Values[vari.Name] = value
		}
	}

	if hasDefaultValues {
		return lit
	}
	return nil
}
Esempio n. 6
0
func isTypeRecursive(typ parser.Type) (bool, []parser.Type) {
	typ = typ.ActualType()

	var check func(current parser.Type, path *[]parser.Type, traversed map[parser.Type]bool) bool
	check = func(current parser.Type, path *[]parser.Type, traversed map[parser.Type]bool) bool {
		switch current.(type) {
		case *parser.NamedType:
			if traversed[current] {
				return true
			}
			traversed[current] = true
		}

		switch current.(type) {
		case parser.StructType:
			st := current.(parser.StructType)
			for _, decl := range st.Variables {
				if check(decl.Variable.Type, path, traversed) {
					*path = append(*path, decl.Variable.Type)
					return true
				}
			}

		case parser.TupleType:
			tt := current.(parser.TupleType)
			for _, mem := range tt.Members {
				if check(mem, path, traversed) {
					*path = append(*path, mem)
					return true
				}
			}

		case parser.EnumType:
			et := current.(parser.EnumType)
			for _, mem := range et.Members {
				if check(mem.Type, path, traversed) {
					*path = append(*path, mem.Type)
					return true
				}
			}

		case *parser.NamedType:
			nt := current.(*parser.NamedType)
			if check(nt.Type, path, traversed) {
				*path = append(*path, nt.Type)
				return true
			}

			// TODO: Add array if we ever add embedded fixed size/static arrays
		}
		return false
	}

	var path []parser.Type
	return check(typ, &path, make(map[parser.Type]bool)), path
}
Esempio n. 7
0
func (v *RecursiveDefinitionCheck) Visit(s *SemanticAnalyzer, n parser.Node) {
	var typ parser.Type

	if typeDecl, ok := n.(*parser.TypeDecl); ok {
		typ = typeDecl.NamedType
	} else {
		return
	}

	if ok, path := isTypeRecursive(typ); ok {
		s.Err(n, "Encountered recursive type definition")

		log.Errorln("semantic", "Path taken:")
		for _, typ := range path {
			log.Error("semantic", typ.TypeName())
			log.Error("semantic", " <- ")
		}
		log.Error("semantic", "%s\n\n", typ.TypeName())
	}

}
Esempio n. 8
0
File: type.go Progetto: vnev/ark
func (v *Codegen) typeToLLVMType(typ parser.Type) llvm.Type {
	switch typ := typ.(type) {
	case parser.PrimitiveType:
		return v.primitiveTypeToLLVMType(typ)
	case parser.FunctionType:
		return v.functionTypeToLLVMType(typ, true)
	case parser.StructType:
		return v.structTypeToLLVMType(typ)
	case parser.PointerType:
		return llvm.PointerType(v.typeToLLVMType(typ.Addressee), 0)
	case parser.ArrayType:
		return v.arrayTypeToLLVMType(typ)
	case parser.TupleType:
		return v.tupleTypeToLLVMType(typ)
	case parser.EnumType:
		return v.enumTypeToLLVMType(typ)
	case *parser.NamedType:
		nt := typ
		switch nt.Type.(type) {
		case parser.StructType, parser.EnumType:
			v.addNamedType(nt)
			lt := v.namedTypeLookup[nt.MangledName(parser.MANGLE_ARK_UNSTABLE)]
			return lt

		default:
			return v.typeToLLVMType(nt.Type)
		}
	case parser.MutableReferenceType:
		return llvm.PointerType(v.typeToLLVMType(typ.Referrer), 0)
	case parser.ConstantReferenceType:
		return llvm.PointerType(v.typeToLLVMType(typ.Referrer), 0)
	default:
		log.Debugln("codegen", "Type was %s (%s)", typ.TypeName(), reflect.TypeOf(typ))
		panic("Unimplemented type category in LLVM codegen")
	}
}
Esempio n. 9
0
File: codegen.go Progetto: vnev/ark
func (v *Codegen) genBinop(operator parser.BinOpType, resType, lhandType, rhandType parser.Type, lhand, rhand llvm.Value) llvm.Value {
	if lhand.IsNil() || rhand.IsNil() {
		v.err("invalid binary expr")
	} else {
		switch operator {
		// Arithmetic
		case parser.BINOP_ADD:
			if resType.IsFloatingType() {
				return v.builder().CreateFAdd(lhand, rhand, "")
			} else {
				return v.builder().CreateAdd(lhand, rhand, "")
			}
		case parser.BINOP_SUB:
			if resType.IsFloatingType() {
				return v.builder().CreateFSub(lhand, rhand, "")
			} else {
				return v.builder().CreateSub(lhand, rhand, "")
			}
		case parser.BINOP_MUL:
			if resType.IsFloatingType() {
				return v.builder().CreateFMul(lhand, rhand, "")
			} else {
				return v.builder().CreateMul(lhand, rhand, "")
			}
		case parser.BINOP_DIV:
			if resType.IsFloatingType() {
				return v.builder().CreateFDiv(lhand, rhand, "")
			} else {
				if resType.(parser.PrimitiveType).IsSigned() {
					return v.builder().CreateSDiv(lhand, rhand, "")
				} else {
					return v.builder().CreateUDiv(lhand, rhand, "")
				}
			}
		case parser.BINOP_MOD:
			if resType.IsFloatingType() {
				return v.builder().CreateFRem(lhand, rhand, "")
			} else {
				if resType.(parser.PrimitiveType).IsSigned() {
					return v.builder().CreateSRem(lhand, rhand, "")
				} else {
					return v.builder().CreateURem(lhand, rhand, "")
				}
			}

		// Comparison
		case parser.BINOP_GREATER, parser.BINOP_LESS, parser.BINOP_GREATER_EQ, parser.BINOP_LESS_EQ, parser.BINOP_EQ, parser.BINOP_NOT_EQ:
			if lhandType.IsFloatingType() {
				return v.builder().CreateFCmp(comparisonOpToFloatPredicate(operator), lhand, rhand, "")
			} else {
				return v.builder().CreateICmp(comparisonOpToIntPredicate(operator, lhandType.IsSigned()), lhand, rhand, "")
			}

		// Bitwise
		case parser.BINOP_BIT_AND:
			return v.builder().CreateAnd(lhand, rhand, "")
		case parser.BINOP_BIT_OR:
			return v.builder().CreateOr(lhand, rhand, "")
		case parser.BINOP_BIT_XOR:
			return v.builder().CreateXor(lhand, rhand, "")
		case parser.BINOP_BIT_LEFT:
			return v.builder().CreateShl(lhand, rhand, "")
		case parser.BINOP_BIT_RIGHT:
			// TODO make sure both operands are same type (create type cast here?)
			// TODO in semantic.go, make sure rhand is *unsigned* (LLVM always treats it that way)
			// TODO doc this
			if lhandType.IsSigned() {
				return v.builder().CreateAShr(lhand, rhand, "")
			} else {
				return v.builder().CreateLShr(lhand, rhand, "")
			}

		default:
			panic("umimplented binop")
		}
	}

	panic("unreachable")
}