예제 #1
0
func (v *Codegen) genAddressOfExpr(n *parser.AddressOfExpr) llvm.Value {
	gep := v.builder.CreateGEP(v.variableLookup[n.Access.Accesses[0].Variable], []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false)}, "")

	for i := 0; i < len(n.Access.Accesses); i++ {

		switch n.Access.Accesses[i].AccessType {
		case parser.ACCESS_ARRAY:
			gepIndexes := []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), 1, false)}
			gep = v.builder.CreateGEP(gep, gepIndexes, "")

			load := v.builder.CreateLoad(gep, "")

			// TODO check that access is in bounds!

			gepIndexes = []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false), v.genExpr(n.Access.Accesses[i].Subscript)}
			gep = v.builder.CreateGEP(load, gepIndexes, "")

		case parser.ACCESS_VARIABLE:
			// nothing to do

		case parser.ACCESS_STRUCT:
			index := n.Access.Accesses[i].Variable.Type.(*parser.StructType).VariableIndex(n.Access.Accesses[i+1].Variable)
			gep = v.builder.CreateGEP(gep, []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false), llvm.ConstInt(llvm.Int32Type(), uint64(index), false)}, "")

		default:
			panic("")
		}
	}

	return gep
}
예제 #2
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, "")
}
예제 #3
0
파일: codegen.go 프로젝트: furryfaust/lyca
func (c *Codegen) generateExpression(node parser.Node) llvm.Value {
	switch n := node.(type) {
	case *parser.BinaryExprNode:
		return c.generateBinaryExpression(n)
	case *parser.NumLitNode:
		if n.IsFloat {
			return llvm.ConstFloat(PRIMITIVE_TYPES["float"], n.FloatValue)
		} else {
			return llvm.ConstInt(PRIMITIVE_TYPES["int"], uint64(n.IntValue), false)
		}
	case *parser.BoolLitNode:
		i := 0
		if n.Value {
			i = 1
		}

		return llvm.ConstInt(PRIMITIVE_TYPES["boolean"], uint64(i), false)
	case *parser.CharLitNode:
		return llvm.ConstInt(PRIMITIVE_TYPES["char"], uint64(n.Value), false)
	case *parser.VarAccessNode, *parser.ObjectAccessNode, *parser.ArrayAccessNode, *parser.CallExprNode, *parser.StringLitNode, *parser.MakeExprNode:
		return c.generateAccess(n, true)
	}

	return null
}
예제 #4
0
파일: stdlib.go 프로젝트: furryfaust/lyca
func (c *Codegen) generateStringConcat(str1, str2 llvm.Value) llvm.Value {
	//    one := llvm.ConstInt(PRIMITIVE_TYPES["int"], 1, false)

	len1 := c.builder.CreateCall(c.module.NamedFunction("-string-len"), []llvm.Value{str1}, "")
	len2 := c.builder.CreateLoad(c.builder.CreateStructGEP(str2, 1, ""), "")
	len_sum := c.builder.CreateAdd(len1, len2, "")

	chars := c.builder.CreateCall(c.module.NamedFunction("malloc"), []llvm.Value{len_sum}, "")
	c.builder.CreateCall(c.module.NamedFunction("llvm.memcpy.p0i8.p0i8.i32"), []llvm.Value{
		chars, c.unbox(str1), len1,
		llvm.ConstInt(PRIMITIVE_TYPES["int"], 0, false),
		llvm.ConstInt(PRIMITIVE_TYPES["boolean"], 0, false),
	}, "")
	c.builder.CreateCall(c.module.NamedFunction("llvm.memcpy.p0i8.p0i8.i32"), []llvm.Value{
		c.builder.CreateGEP(chars, []llvm.Value{len1}, ""), c.unbox(str2), len2,
		llvm.ConstInt(PRIMITIVE_TYPES["int"], 0, false),
		llvm.ConstInt(PRIMITIVE_TYPES["boolean"], 0, false),
	}, "")

	str := c.builder.CreateMalloc(c.templates["string"].Type, "")
	c.builder.CreateStore(chars, c.builder.CreateStructGEP(str, 0, ""))
	c.builder.CreateStore(len_sum, c.builder.CreateStructGEP(str, 1, ""))
	c.builder.CreateStore(len_sum, c.builder.CreateStructGEP(str, 2, ""))

	return str
}
예제 #5
0
파일: channels.go 프로젝트: glycerine/llgo
func (fr *frame) chanSelect(sel *ssa.Select) (index, recvOk *govalue, recvElems []*govalue) {
	n := uint64(len(sel.States))
	if !sel.Blocking {
		// non-blocking means there's a default case
		n++
	}
	size := llvm.ConstInt(llvm.Int32Type(), n, false)
	selectp := fr.runtime.newSelect.call(fr, size)[0]

	// Allocate stack for the values to send and receive.
	ptrs := make([]llvm.Value, len(sel.States))
	for i, state := range sel.States {
		chantyp := state.Chan.Type().Underlying().(*types.Chan)
		elemtyp := fr.types.ToLLVM(chantyp.Elem())
		if state.Dir == types.SendOnly {
			ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "")
			fr.builder.CreateStore(fr.llvmvalue(state.Send), ptrs[i])
		} else {
			// Only allocate stack space if the received value is used.
			used := chanSelectStateUsed(sel, len(recvElems))
			if used {
				ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "")
			} else {
				ptrs[i] = llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0))
			}
			recvElems = append(recvElems, newValue(ptrs[i], chantyp.Elem()))
		}
	}

	// Create select{send,recv2} calls.
	var receivedp llvm.Value
	if len(recvElems) > 0 {
		receivedp = fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(types.Typ[types.Bool]), "")
	}
	if !sel.Blocking {
		// If the default case is chosen, the index must be -1.
		fr.runtime.selectdefault.call(fr, selectp, llvm.ConstAllOnes(llvm.Int32Type()))
	}
	for i, state := range sel.States {
		ch := fr.llvmvalue(state.Chan)
		index := llvm.ConstInt(llvm.Int32Type(), uint64(i), false)
		if state.Dir == types.SendOnly {
			fr.runtime.selectsend.call(fr, selectp, ch, ptrs[i], index)
		} else {
			fr.runtime.selectrecv2.call(fr, selectp, ch, ptrs[i], receivedp, index)
		}
	}

	// Fire off the select.
	index = newValue(fr.runtime.selectgo.call(fr, selectp)[0], types.Typ[types.Int])
	if len(recvElems) > 0 {
		recvOk = newValue(fr.builder.CreateLoad(receivedp, ""), types.Typ[types.Bool])
		for _, recvElem := range recvElems {
			recvElem.value = fr.builder.CreateLoad(recvElem.value, "")
		}
	}
	return index, recvOk, recvElems
}
예제 #6
0
파일: codegen.go 프로젝트: IanMurray/ark
func (v *Codegen) genAccessGEP(n parser.Expr) llvm.Value {
	switch access := n.(type) {
	case *parser.VariableAccessExpr:
		varType := v.getVariable(access.Variable)
		log.Debugln("codegen", "%v => %v", access.Variable, varType)
		if varType.IsNil() {
			panic("varType was nil")
		}
		gep := v.builder().CreateGEP(varType, []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false)}, "")

		if _, ok := access.GetType().(parser.MutableReferenceType); ok {
			return v.builder().CreateLoad(gep, "")
		}

		if _, ok := access.GetType().(parser.ConstantReferenceType); ok {
			return v.builder().CreateLoad(gep, "")
		}

		return gep

	case *parser.StructAccessExpr:
		gep := v.genAccessGEP(access.Struct)

		typ := access.Struct.GetType().ActualType()

		index := typ.(parser.StructType).VariableIndex(access.Variable)
		return v.builder().CreateStructGEP(gep, index, "")

	case *parser.ArrayAccessExpr:
		gep := v.genAccessGEP(access.Array)
		subscriptExpr := v.genExpr(access.Subscript)

		v.genBoundsCheck(v.builder().CreateLoad(v.builder().CreateStructGEP(gep, 0, ""), ""),
			subscriptExpr, access.Subscript.GetType())

		gep = v.builder().CreateStructGEP(gep, 1, "")

		load := v.builder().CreateLoad(gep, "")

		gepIndexes := []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false), subscriptExpr}
		return v.builder().CreateGEP(load, gepIndexes, "")

	case *parser.TupleAccessExpr:
		gep := v.genAccessGEP(access.Tuple)

		// TODO: Check overflow
		return v.builder().CreateStructGEP(gep, int(access.Index), "")

	case *parser.DerefAccessExpr:
		return v.genExpr(access.Expr)

	default:
		panic("unhandled access type")
	}
}
예제 #7
0
파일: errors.go 프로젝트: hinike/llgo
func (fr *frame) setBranchWeightMetadata(br llvm.Value, trueweight, falseweight uint64) {
	mdprof := llvm.MDKindID("prof")

	mdnode := llvm.MDNode([]llvm.Value{
		llvm.MDString("branch_weights"),
		llvm.ConstInt(llvm.Int32Type(), trueweight, false),
		llvm.ConstInt(llvm.Int32Type(), falseweight, false),
	})

	br.SetMetadata(mdprof, mdnode)
}
예제 #8
0
파일: channels.go 프로젝트: hinike/llgo
func (fr *frame) chanSelect(states []selectState, blocking bool) (index, recvOk *govalue, recvElems []*govalue) {
	n := uint64(len(states))
	if !blocking {
		// non-blocking means there's a default case
		n++
	}
	size := llvm.ConstInt(llvm.Int32Type(), n, false)
	selectp := fr.runtime.newSelect.call(fr, size)[0]

	// Allocate stack for the values to send and receive.
	//
	// TODO(axw) check if received elements have any users, and
	// elide stack allocation if not (pass nil to recv2 instead.)
	ptrs := make([]llvm.Value, len(states))
	for i, state := range states {
		chantyp := state.Chan.Type().Underlying().(*types.Chan)
		elemtyp := fr.types.ToLLVM(chantyp.Elem())
		ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "")
		if state.Dir == types.SendOnly {
			fr.builder.CreateStore(state.Send.value, ptrs[i])
		} else {
			recvElems = append(recvElems, newValue(ptrs[i], chantyp.Elem()))
		}
	}

	// Create select{send,recv2} calls.
	var receivedp llvm.Value
	if len(recvElems) > 0 {
		receivedp = fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(types.Typ[types.Bool]), "")
	}
	if !blocking {
		// If the default case is chosen, the index must be -1.
		fr.runtime.selectdefault.call(fr, selectp, llvm.ConstAllOnes(llvm.Int32Type()))
	}
	for i, state := range states {
		ch := state.Chan.value
		index := llvm.ConstInt(llvm.Int32Type(), uint64(i), false)
		if state.Dir == types.SendOnly {
			fr.runtime.selectsend.call(fr, selectp, ch, ptrs[i], index)
		} else {
			fr.runtime.selectrecv2.call(fr, selectp, ch, ptrs[i], receivedp, index)
		}
	}

	// Fire off the select.
	index = newValue(fr.runtime.selectgo.call(fr, selectp)[0], types.Typ[types.Int])
	if len(recvElems) > 0 {
		recvOk = newValue(fr.builder.CreateLoad(receivedp, ""), types.Typ[types.Bool])
		for _, recvElem := range recvElems {
			recvElem.value = fr.builder.CreateLoad(recvElem.value, "")
		}
	}
	return index, recvOk, recvElems
}
예제 #9
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)
	}
}
예제 #10
0
파일: builtins.go 프로젝트: glycerine/llgo
func (fr *frame) callCap(arg *govalue) *govalue {
	var v llvm.Value
	switch typ := arg.Type().Underlying().(type) {
	case *types.Array:
		v = llvm.ConstInt(fr.llvmtypes.inttype, uint64(typ.Len()), false)
	case *types.Pointer:
		atyp := typ.Elem().Underlying().(*types.Array)
		v = llvm.ConstInt(fr.llvmtypes.inttype, uint64(atyp.Len()), false)
	case *types.Slice:
		v = fr.builder.CreateExtractValue(arg.value, 2, "")
	case *types.Chan:
		v = fr.runtime.chanCap.call(fr, arg.value)[0]
	}
	return newValue(v, types.Typ[types.Int])
}
예제 #11
0
파일: codegen.go 프로젝트: dansawkins/ark
func (v *Codegen) genAccessGEP(n parser.Expr) llvm.Value {
	switch n.(type) {
	case *parser.VariableAccessExpr:
		vae := n.(*parser.VariableAccessExpr)
		return v.builder.CreateGEP(v.variableLookup[vae.Variable], []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false)}, "")

	case *parser.StructAccessExpr:
		sae := n.(*parser.StructAccessExpr)

		gep := v.genAccessGEP(sae.Struct)

		typ := sae.Struct.GetType().ActualType()

		index := typ.(*parser.StructType).VariableIndex(sae.Variable)
		return v.builder.CreateStructGEP(gep, index, "")

	case *parser.ArrayAccessExpr:
		aae := n.(*parser.ArrayAccessExpr)

		gep := v.genAccessGEP(aae.Array)
		subscriptExpr := v.genExpr(aae.Subscript)

		v.genBoundsCheck(v.builder.CreateLoad(v.builder.CreateStructGEP(gep, 0, ""), ""), subscriptExpr, aae.Subscript.GetType())

		gep = v.builder.CreateStructGEP(gep, 1, "")

		load := v.builder.CreateLoad(gep, "")

		gepIndexes := []llvm.Value{llvm.ConstInt(llvm.Int32Type(), 0, false), subscriptExpr}
		return v.builder.CreateGEP(load, gepIndexes, "")

	case *parser.TupleAccessExpr:
		tae := n.(*parser.TupleAccessExpr)

		gep := v.genAccessGEP(tae.Tuple)

		// TODO: Check overflow
		return v.builder.CreateStructGEP(gep, int(tae.Index), "")

	case *parser.DerefAccessExpr:
		dae := n.(*parser.DerefAccessExpr)

		return v.genExpr(dae.Expr)

	default:
		panic("unhandled access type")
	}
}
예제 #12
0
파일: codegen.go 프로젝트: vnev/ark
func (v *Codegen) genNumericLiteral(n *parser.NumericLiteral) llvm.Value {
	if n.Type.IsFloatingType() {
		return llvm.ConstFloat(v.typeToLLVMType(n.Type), n.AsFloat())
	} else {
		return llvm.ConstInt(v.typeToLLVMType(n.Type), n.AsInt(), false)
	}
}
예제 #13
0
파일: codegen.go 프로젝트: 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)
}
예제 #14
0
// interfaceMethod returns a function and receiver pointer for the specified
// interface and method pair.
func (fr *frame) interfaceMethod(lliface llvm.Value, ifacety types.Type, method *types.Func) (fn, recv *govalue) {
	llitab := fr.builder.CreateExtractValue(lliface, 0, "")
	recv = newValue(fr.builder.CreateExtractValue(lliface, 1, ""), types.Typ[types.UnsafePointer])
	methodset := fr.types.MethodSet(ifacety)
	// TODO(axw) cache ordered method index
	index := -1
	for i, m := range orderedMethodSet(methodset) {
		if m.Obj() == method {
			index = i
			break
		}
	}
	if index == -1 {
		panic("could not find method index")
	}
	llitab = fr.builder.CreateBitCast(llitab, llvm.PointerType(llvm.PointerType(llvm.Int8Type(), 0), 0), "")
	// Skip runtime type pointer.
	llifnptr := fr.builder.CreateGEP(llitab, []llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(index+1), false),
	}, "")

	llifn := fr.builder.CreateLoad(llifnptr, "")
	// Replace receiver type with unsafe.Pointer.
	recvparam := types.NewParam(0, nil, "", types.Typ[types.UnsafePointer])
	sig := method.Type().(*types.Signature)
	sig = types.NewSignature(nil, recvparam, sig.Params(), sig.Results(), sig.Variadic())
	fn = newValue(llifn, sig)
	return
}
예제 #15
0
파일: errors.go 프로젝트: hinike/llgo
func (fr *frame) condBrRuntimeError(cond llvm.Value, errcode uint64) {
	if cond.IsNull() {
		return
	}

	errorbb := fr.runtimeErrorBlocks[errcode]
	newbb := errorbb.C == nil
	if newbb {
		errorbb = llvm.AddBasicBlock(fr.function, "")
		fr.runtimeErrorBlocks[errcode] = errorbb
	}

	contbb := llvm.AddBasicBlock(fr.function, "")

	br := fr.builder.CreateCondBr(cond, errorbb, contbb)
	fr.setBranchWeightMetadata(br, 1, 1000)

	if newbb {
		fr.builder.SetInsertPointAtEnd(errorbb)
		fr.runtime.runtimeError.call(fr, llvm.ConstInt(llvm.Int32Type(), errcode, false))
		fr.builder.CreateUnreachable()
	}

	fr.builder.SetInsertPointAtEnd(contbb)
}
예제 #16
0
파일: ssa.go 프로젝트: glycerine/llgo
// emitInitPrologue emits the init-specific function prologue (guard check and
// initialization of dependent packages under the llgo native ABI), and returns
// the basic block into which the GC registration call should be emitted.
func (fr *frame) emitInitPrologue() llvm.BasicBlock {
	if fr.GccgoABI {
		return fr.builder.GetInsertBlock()
	}

	initGuard := llvm.AddGlobal(fr.module.Module, llvm.Int1Type(), "init$guard")
	initGuard.SetLinkage(llvm.InternalLinkage)
	initGuard.SetInitializer(llvm.ConstNull(llvm.Int1Type()))

	returnBlock := llvm.AddBasicBlock(fr.function, "")
	initBlock := llvm.AddBasicBlock(fr.function, "")

	initGuardVal := fr.builder.CreateLoad(initGuard, "")
	fr.builder.CreateCondBr(initGuardVal, returnBlock, initBlock)

	fr.builder.SetInsertPointAtEnd(returnBlock)
	fr.builder.CreateRetVoid()

	fr.builder.SetInsertPointAtEnd(initBlock)
	fr.builder.CreateStore(llvm.ConstInt(llvm.Int1Type(), 1, false), initGuard)
	int8ptr := llvm.PointerType(fr.types.ctx.Int8Type(), 0)
	ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false)
	for _, pkg := range fr.pkg.Object.Imports() {
		initname := ManglePackagePath(pkg.Path()) + "..import"
		initfn := fr.module.Module.NamedFunction(initname)
		if initfn.IsNil() {
			initfn = llvm.AddFunction(fr.module.Module, initname, ftyp)
		}
		args := []llvm.Value{llvm.Undef(int8ptr)}
		fr.builder.CreateCall(initfn, args, "")
	}

	return initBlock
}
예제 #17
0
파일: codegen.go 프로젝트: 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())
}
예제 #18
0
파일: stdlib.go 프로젝트: furryfaust/lyca
func (c *Codegen) stdString() {
	tmpl := &Template{
		Type:      llvm.GlobalContext().StructCreateNamed("string"),
		Variables: map[string]int{},
	}
	c.templates["string"] = tmpl

	vars := []llvm.Type{
		llvm.PointerType(PRIMITIVE_TYPES["char"], 0),
		PRIMITIVE_TYPES["int"],
		PRIMITIVE_TYPES["int"],
	}
	tmpl.Type.StructSetBody(vars, false)

	lenFuncType := llvm.FunctionType(PRIMITIVE_TYPES["int"], []llvm.Type{llvm.PointerType(tmpl.Type, 0)}, false)
	lenFunc := llvm.AddFunction(c.module, "-string-len", lenFuncType)
	lenFunc.Param(0).SetName("this")
	block := llvm.AddBasicBlock(c.module.NamedFunction("-string-len"), "entry")
	c.functions["-string-len"] = block
	c.currFunc = "-string-len"
	c.builder.SetInsertPoint(block, block.LastInstruction())
	ret := c.builder.CreateStructGEP(c.getCurrParam("this"), 1, "")
	ret = c.builder.CreateLoad(ret, "")
	ret = c.builder.CreateSub(ret, llvm.ConstInt(PRIMITIVE_TYPES["int"], 1, false), "")
	c.builder.CreateRet(ret)

	printFuncType := llvm.FunctionType(PRIMITIVE_TYPES["int"], []llvm.Type{
		llvm.PointerType(PRIMITIVE_TYPES["char"], 0),
	}, true)
	llvm.AddFunction(c.module, "printf", printFuncType)
}
예제 #19
0
파일: codegen.go 프로젝트: 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
}
예제 #20
0
파일: ssa.go 프로젝트: hinike/llgo
// If this value is sufficiently large, look through referrers to see if we can
// avoid a load.
func (fr *frame) canAvoidLoad(instr *ssa.UnOp, op llvm.Value) bool {
	if fr.types.Sizeof(instr.Type()) < 16 {
		// Don't bother with small values.
		return false
	}

	// Keep track of whether our pointer may escape. We conservatively assume
	// that MakeInterfaces will escape.
	esc := false

	// We only know how to avoid loads if they are used to create an interface
	// or read an element of the structure. If we see any other referrer, abort.
	for _, ref := range *instr.Referrers() {
		switch ref.(type) {
		case *ssa.MakeInterface:
			esc = true
		case *ssa.Field, *ssa.Index:
			// ok
		default:
			return false
		}
	}

	var opcopy llvm.Value
	if esc {
		opcopy = fr.createTypeMalloc(instr.Type())
	} else {
		opcopy = fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(instr.Type()), "")
	}
	fr.memcpy(opcopy, op, llvm.ConstInt(fr.types.inttype, uint64(fr.types.Sizeof(instr.Type())), false))

	fr.ptr[instr] = opcopy
	return true
}
예제 #21
0
파일: builtins.go 프로젝트: glycerine/llgo
// callAppend takes two slices of the same type, and yields
// the result of appending the second to the first.
func (fr *frame) callAppend(a, b *govalue) *govalue {
	bptr := fr.builder.CreateExtractValue(b.value, 0, "")
	blen := fr.builder.CreateExtractValue(b.value, 1, "")
	elemsizeInt64 := fr.types.Sizeof(a.Type().Underlying().(*types.Slice).Elem())
	elemsize := llvm.ConstInt(fr.target.IntPtrType(), uint64(elemsizeInt64), false)
	result := fr.runtime.append.call(fr, a.value, bptr, blen, elemsize)[0]
	return newValue(result, a.Type())
}
예제 #22
0
파일: codegen.go 프로젝트: 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")
	}
}
예제 #23
0
파일: debug.go 프로젝트: hinike/llgo
// SetLocation sets the current debug location.
func (d *DIBuilder) SetLocation(b llvm.Builder, pos token.Pos) {
	if !pos.IsValid() {
		return
	}
	position := d.fset.Position(pos)
	d.lb = llvm.Value{nil}
	if position.Filename != d.fnFile && position.Filename != "" {
		// This can happen rarely, e.g. in init functions.
		diFile := d.builder.CreateFile(d.remapFilePath(position.Filename), "")
		d.lb = d.builder.CreateLexicalBlockFile(d.scope(), diFile, 0)
	}
	b.SetCurrentDebugLocation(llvm.MDNode([]llvm.Value{
		llvm.ConstInt(llvm.Int32Type(), uint64(position.Line), false),
		llvm.ConstInt(llvm.Int32Type(), uint64(position.Column), false),
		d.scope(),
		llvm.Value{},
	}))
}
예제 #24
0
파일: runtime.go 프로젝트: glycerine/llgo
func (fr *frame) memcpy(dest llvm.Value, src llvm.Value, size llvm.Value) {
	memcpy := fr.runtime.memcpy
	dest = fr.builder.CreateBitCast(dest, llvm.PointerType(llvm.Int8Type(), 0), "")
	src = fr.builder.CreateBitCast(src, llvm.PointerType(llvm.Int8Type(), 0), "")
	size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "")
	align := llvm.ConstInt(llvm.Int32Type(), 1, false)
	isvolatile := llvm.ConstNull(llvm.Int1Type())
	fr.builder.CreateCall(memcpy, []llvm.Value{dest, src, size, align, isvolatile}, "")
}
예제 #25
0
파일: runtime.go 프로젝트: glycerine/llgo
func (fr *frame) memsetZero(ptr llvm.Value, size llvm.Value) {
	memset := fr.runtime.memset
	ptr = fr.builder.CreateBitCast(ptr, llvm.PointerType(llvm.Int8Type(), 0), "")
	fill := llvm.ConstNull(llvm.Int8Type())
	size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "")
	align := llvm.ConstInt(llvm.Int32Type(), 1, false)
	isvolatile := llvm.ConstNull(llvm.Int1Type())
	fr.builder.CreateCall(memset, []llvm.Value{ptr, fill, size, align, isvolatile}, "")
}
예제 #26
0
func (v *Codegen) genBoolLiteral(n *parser.BoolLiteral) llvm.Value {
	var num uint64

	if n.Value {
		num = 1
	}

	return llvm.ConstInt(v.typeToLLVMType(n.GetType()), num, true)
}
예제 #27
0
파일: debug.go 프로젝트: glycerine/llgo
// Finalize must be called after all compilation units are translated,
// generating the final debug metadata for the module.
func (d *DIBuilder) Finalize() {
	d.module.AddNamedMetadataOperand(
		"llvm.module.flags",
		llvm.GlobalContext().MDNode([]llvm.Metadata{
			llvm.ConstInt(llvm.Int32Type(), 2, false).ConstantAsMetadata(), // Warn on mismatch
			llvm.GlobalContext().MDString("Dwarf Version"),
			llvm.ConstInt(llvm.Int32Type(), 4, false).ConstantAsMetadata(),
		}),
	)
	d.module.AddNamedMetadataOperand(
		"llvm.module.flags",
		llvm.GlobalContext().MDNode([]llvm.Metadata{
			llvm.ConstInt(llvm.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch
			llvm.GlobalContext().MDString("Debug Info Version"),
			llvm.ConstInt(llvm.Int32Type(), 2, false).ConstantAsMetadata(),
		}),
	)
	d.builder.Finalize()
}
예제 #28
0
파일: ssa.go 프로젝트: hinike/llgo
func (u *unit) addGlobal(global llvm.Value, ty types.Type) {
	u.globalInits[global] = new(globalInit)

	if hasPointers(ty) {
		global = llvm.ConstBitCast(global, llvm.PointerType(llvm.Int8Type(), 0))
		size := llvm.ConstInt(u.types.inttype, uint64(u.types.Sizeof(ty)), false)
		root := llvm.ConstStruct([]llvm.Value{global, size}, false)
		u.gcRoots = append(u.gcRoots, root)
	}
}
예제 #29
0
파일: codegen.go 프로젝트: vnev/ark
func (v *Codegen) genSizeofExpr(n *parser.SizeofExpr) llvm.Value {
	var typ llvm.Type

	if n.Expr != nil {
		typ = v.typeToLLVMType(n.Expr.GetType())
	} else {
		typ = v.typeToLLVMType(n.Type)
	}

	return llvm.ConstInt(v.targetData.IntPtrType(), v.targetData.TypeAllocSize(typ), false)
}
예제 #30
0
파일: codegen.go 프로젝트: vnev/ark
func (v *Codegen) genRaiseSegfault() {
	fn := v.curFile.LlvmModule.NamedFunction("raise")
	intType := v.typeToLLVMType(parser.PRIMITIVE_int)

	if fn.IsNil() {
		fnType := llvm.FunctionType(intType, []llvm.Type{intType}, false)
		fn = llvm.AddFunction(v.curFile.LlvmModule, "raise", fnType)
	}

	v.builder().CreateCall(fn, []llvm.Value{llvm.ConstInt(intType, 11, false)}, "segfault")
}