Esempio n. 1
0
func (n *VarExpr) Gen(cg *CG) llvm.Value {
	fun := cg.GetInsertBlock().Parent()

	var oldBindingNames []string
	var oldBindingValues []llvm.Value
	for name, init := range n.Names {
		var initVal llvm.Value
		if init != nil {
			init.Gen(cg)
			if initVal.IsNil() {
				return llvm.Value{}
			}
		} else {
			initVal = llvm.ConstFloat(cg.FloatType(), 0)
		}

		alloca := createEntryBlockAlloca(fun, name)
		cg.CreateStore(initVal, alloca)

		oldBindingNames = append(oldBindingNames, name)
		oldBindingValues = append(oldBindingValues, cg.NamedValues[name])
		cg.NamedValues[name] = alloca
	}

	bodyVal := n.Body.Gen(cg)
	if bodyVal.IsNil() {
		return llvm.Value{}
	}

	for i, name := range oldBindingNames {
		cg.NamedValues[name] = oldBindingValues[i]
	}

	return bodyVal
}
Esempio n. 2
0
func (c *Codegen) generateArithmeticBinaryExpr(left, right llvm.Value, op string) llvm.Value {
	t := c.getUnderlyingType(left.Type())
	switch op {
	case "+":
		if t == PRIMITIVE_TYPES["float"] {
			return c.builder.CreateFAdd(left, right, "")
		} else if t == PRIMITIVE_TYPES["int"] {
			return c.builder.CreateAdd(left, right, "")
		} else if t == c.templates["string"].Type {
			return c.generateStringConcat(left, right)
		}
	case "-":
		if t == PRIMITIVE_TYPES["float"] {
			return c.builder.CreateFSub(left, right, "")
		} else if t == PRIMITIVE_TYPES["int"] {
			return c.builder.CreateSub(left, right, "")
		}
	case "*":
		if t == PRIMITIVE_TYPES["float"] {
			return c.builder.CreateFMul(left, right, "")
		} else if t == PRIMITIVE_TYPES["int"] {
			return c.builder.CreateMul(left, right, "")
		}
	case "/":
		if t == PRIMITIVE_TYPES["float"] {
			return c.builder.CreateFDiv(left, right, "")
		} else if t == PRIMITIVE_TYPES["int"] {
			return c.builder.CreateSDiv(left, right, "")
		}
	}

	return null
}
Esempio n. 3
0
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)
}
Esempio n. 4
0
func (c *Codegen) generateVarDecl(node *parser.VarDeclNode, global bool) {
	t := c.getLLVMType(node.Type)
	name := node.Name.Value
	if c.scope.Declared(name) {
		// Error name has already been declared
	}

	var alloc, val llvm.Value
	if node.Value == nil {
		if t.TypeKind() == llvm.PointerTypeKind {
			val = c.convert(c.scope.GetValue("null"), t)
		} else {
			val = llvm.Undef(t)
		}
	} else {
		val = c.convert(c.generateExpression(node.Value), t)
	}

	if !global {
		alloc = c.builder.CreateAlloca(t, name)
		c.builder.CreateStore(val, alloc)
	} else {
		alloc = llvm.AddGlobal(c.module, t, name)
		alloc.SetInitializer(val)
	}

	c.scope.AddVariable(name, alloc)
}
Esempio n. 5
0
File: cabi.go Progetto: hinike/llgo
func directEncode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, argTypes []llvm.Type, args []llvm.Value, val llvm.Value) {
	valType := val.Type()

	switch len(argTypes) {
	case 0:
		// do nothing

	case 1:
		if argTypes[0].C == valType.C {
			args[0] = val
			return
		}
		alloca := allocaBuilder.CreateAlloca(valType, "")
		bitcast := builder.CreateBitCast(alloca, llvm.PointerType(argTypes[0], 0), "")
		builder.CreateStore(val, alloca)
		args[0] = builder.CreateLoad(bitcast, "")

	case 2:
		encodeType := llvm.StructType(argTypes, false)
		alloca := allocaBuilder.CreateAlloca(valType, "")
		bitcast := builder.CreateBitCast(alloca, llvm.PointerType(encodeType, 0), "")
		builder.CreateStore(val, alloca)
		args[0] = builder.CreateLoad(builder.CreateStructGEP(bitcast, 0, ""), "")
		args[1] = builder.CreateLoad(builder.CreateStructGEP(bitcast, 1, ""), "")

	default:
		panic("unexpected argTypes size")
	}
}
Esempio n. 6
0
File: codegen.go Progetto: vnev/ark
func (v *Codegen) genFunctionBody(fn *parser.Function, llvmFn llvm.Value) {
	block := llvm.AddBasicBlock(llvmFn, "entry")

	v.pushFunction(fn)
	v.builders[v.currentFunction()] = llvm.NewBuilder()
	v.builder().SetInsertPointAtEnd(block)

	pars := fn.Parameters

	if fn.Type.Receiver != nil {
		newPars := make([]*parser.VariableDecl, len(pars)+1)
		newPars[0] = fn.Receiver
		copy(newPars[1:], pars)
		pars = newPars
	}

	for i, par := range pars {
		alloc := v.builder().CreateAlloca(v.typeToLLVMType(par.Variable.Type), par.Variable.Name)
		v.variableLookup[par.Variable] = alloc

		v.builder().CreateStore(llvmFn.Params()[i], alloc)
	}

	v.genBlock(fn.Body)
	v.builder().Dispose()
	delete(v.builders, v.currentFunction())
	delete(v.curLoopExits, v.currentFunction())
	delete(v.curLoopNexts, v.currentFunction())
	v.popFunction()
}
Esempio n. 7
0
func (fr *frame) createZExtOrTrunc(v llvm.Value, t llvm.Type, name string) llvm.Value {
	switch n := v.Type().IntTypeWidth() - t.IntTypeWidth(); {
	case n < 0:
		v = fr.builder.CreateZExt(v, fr.target.IntPtrType(), name)
	case n > 0:
		v = fr.builder.CreateTrunc(v, fr.target.IntPtrType(), name)
	}
	return v
}
Esempio n. 8
0
func (c *Codegen) unbox(val llvm.Value) llvm.Value {
	t := c.getUnderlyingType(val.Type())
	switch t {
	case c.templates["string"].Type:
		val = c.builder.CreateStructGEP(val, 0, "")
		val = c.builder.CreateLoad(val, "")
	}

	return val
}
Esempio n. 9
0
func (n *ForExpr) Gen(cg *CG) llvm.Value {
	startVal := n.Start.Gen(cg)
	if startVal.IsNil() {
		return errv("Code generation failed for start expression")
	}

	fun := cg.GetInsertBlock().Parent()
	alloca := createEntryBlockAlloca(fun, n.Var)
	cg.CreateStore(startVal, alloca)

	loopBB := llvm.AddBasicBlock(fun, "loop")
	cg.CreateBr(loopBB)
	cg.SetInsertPointAtEnd(loopBB)

	oldVal := cg.NamedValues[n.Var]
	cg.NamedValues[n.Var] = alloca

	if n.Body.Gen(cg).IsNil() {
		return llvm.Value{}
	}

	var stepVal llvm.Value
	if n.Step != nil {
		stepVal = n.Step.Gen(cg)
		if stepVal.IsNil() {
			return llvm.ConstNull(llvm.DoubleType())
		}
	} else {
		stepVal = llvm.ConstFloat(llvm.DoubleType(), 1)
	}

	endVal := n.End.Gen(cg)
	if endVal.IsNil() {
		return llvm.Value{}
	}

	curVar := cg.CreateLoad(alloca, n.Var)
	nextVar := cg.CreateFAdd(curVar, stepVal, "nextvar")
	cg.CreateStore(nextVar, alloca)

	endVal = cg.CreateFCmp(llvm.FloatONE, endVal, llvm.ConstFloat(llvm.DoubleType(), 0), "loopcond")
	afterBB := cg.AddBasicBlock(fun, "afterloop")

	cg.CreateCondBr(endVal, loopBB, afterBB)

	cg.SetInsertPointAtEnd(afterBB)

	if !oldVal.IsNil() {
		cg.NamedValues[n.Var] = oldVal
	} else {
		delete(cg.NamedValues, n.Var)
	}

	return llvm.ConstFloat(llvm.DoubleType(), 0)
}
Esempio n. 10
0
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)
}
Esempio n. 11
0
File: codegen.go Progetto: 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")
	}
}
Esempio n. 12
0
// hackDump returns the value dump as a string.
func hackDump(v llvm.Value) (string, error) {
	// Open temp file.
	// TODO: Use an in-memory file instead of /tmp/x.
	fd, err := unix.Open("/tmp/x", unix.O_WRONLY|unix.O_TRUNC|unix.O_CREAT, 0644)
	if err != nil {
		return "", errutil.Err(err)
	}

	// Store original stderr.
	stderr, err := unix.Dup(2)
	if err != nil {
		return "", errutil.Err(err)
	}

	// Capture stderr and redirect its output to the temp file.
	err = unix.Dup2(fd, 2)
	if err != nil {
		return "", errutil.Err(err)
	}
	err = unix.Close(fd)
	if err != nil {
		return "", errutil.Err(err)
	}

	// Dump value.
	v.Dump()
	C.fflush_stderr()

	// Restore stderr.
	err = unix.Dup2(stderr, 2)
	if err != nil {
		return "", errutil.Err(err)
	}
	err = unix.Close(stderr)
	if err != nil {
		return "", errutil.Err(err)
	}

	// Return content of temp file.
	buf, err := ioutil.ReadFile("/tmp/x")
	if err != nil {
		return "", errutil.Err(err)
	}
	return string(buf), nil
}
Esempio n. 13
0
// parseOperand converts the provided LLVM IR operand into an equivalent Go AST
// expression node (a basic literal, a composite literal or an identifier).
//
// Syntax:
//    i32 1
//    %foo = ...
func parseOperand(op llvm.Value) (ast.Expr, error) {
	// TODO: Support *BasicLit, *CompositeLit.

	// Parse and validate tokens.
	tokens, err := getTokens(op)
	if err != nil {
		return nil, err
	}
	if len(tokens) < 2 {
		// TODO: Remove debug output.
		op.Dump()
		return nil, errutil.Newf("unable to parse operand; expected 2 >= tokens, got %d", len(tokens))
	}

	// TODO: Add support for operand of other types than int.
	// TODO: Parse type.

	// Create and return a constant operand.
	//    i32 42
	if tokens[0].Kind == lltoken.Type {
		switch tok := tokens[1]; tok.Kind {
		case lltoken.Int:
			return &ast.BasicLit{Kind: token.INT, Value: tok.Val}, nil
		case lltoken.LocalVar:
			return getIdent(tok)
		default:
			return nil, errutil.Newf("support for LLVM IR token kind %v not yet implemented", tok.Kind)
		}
	}

	// Create and return a variable operand.
	//    %foo = ...
	if tokens[1].Kind == lltoken.Equal {
		switch tok := tokens[0]; tok.Kind {
		case lltoken.LocalVar, lltoken.LocalID:
			//    %foo
			//    %42
			return getIdent(tok)
		default:
			return nil, errutil.Newf("support for LLVM IR token kind %v not yet implemented", tok.Kind)
		}
	}

	return nil, errutil.New("support for LLVM IR operand not yet implemented")
}
Esempio n. 14
0
// PushFunction creates debug metadata for the specified function,
// and pushes it onto the scope stack.
func (d *DIBuilder) PushFunction(fnptr llvm.Value, sig *types.Signature, pos token.Pos) {
	var diFile llvm.Metadata
	var line int
	if file := d.fset.File(pos); file != nil {
		d.fnFile = file.Name()
		diFile = d.getFile(file)
		line = file.Line(pos)
	}
	d.fn = d.builder.CreateFunction(d.scope(), llvm.DIFunction{
		Name:         fnptr.Name(), // TODO(axw) unmangled name?
		LinkageName:  fnptr.Name(),
		File:         diFile,
		Line:         line,
		Type:         d.DIType(sig),
		IsDefinition: true,
	})
	fnptr.SetSubprogram(d.fn)
}
Esempio n. 15
0
// parseBinOp converts the provided LLVM IR binary operation into an equivalent
// Go AST node (an assignment statement with a binary expression on the right-
// hand side).
//
// Syntax:
//    <result> add <type> <op1>, <op2>
//
// References:
//    http://llvm.org/docs/LangRef.html#binary-operations
func parseBinOp(inst llvm.Value, op token.Token) (ast.Stmt, error) {
	x, err := parseOperand(inst.Operand(0))
	if err != nil {
		return nil, err
	}
	y, err := parseOperand(inst.Operand(1))
	if err != nil {
		return nil, err
	}
	result, err := getResult(inst)
	if err != nil {
		return nil, errutil.Err(err)
	}
	lhs := []ast.Expr{result}
	rhs := []ast.Expr{&ast.BinaryExpr{X: x, Op: op, Y: y}}
	// TODO: Use "=" instead of ":=" and let go-post and grind handle the ":=" to
	// "=" propagation.
	return &ast.AssignStmt{Lhs: lhs, Tok: token.DEFINE, Rhs: rhs}, nil
}
Esempio n. 16
0
func (c *Codegen) convert(val llvm.Value, t llvm.Type) llvm.Value {
	if val.Type() == t {
		return val
	}

	if val == c.scope.GetValue("null") {
		log.Println("Null conversion")
		return llvm.ConstPointerNull(t)
	}

	switch val.Type() {
	case PRIMITIVE_TYPES["int"]:
		if t == PRIMITIVE_TYPES["float"] {
			return c.builder.CreateSIToFP(val, t, "")
		}
	}

	return val
}
Esempio n. 17
0
// addTerm adds the provided terminator instruction to the basic block. If the
// terminator instruction doesn't have a target basic block (e.g. ret) it is
// parsed and added to the statements list of the basic block instead.
func (bb *basicBlock) addTerm(term llvm.Value) error {
	// TODO: Check why there is no opcode in the llvm library for the resume
	// terminator instruction.
	switch opcode := term.InstructionOpcode(); opcode {
	case llvm.Ret:
		// The return instruction doesn't have any target basic blocks so treat it
		// like a regular instruction and append it to the list of statements.
		ret, err := parseRetInst(term)
		if err != nil {
			return err
		}
		bb.stmts = append(bb.stmts, ret)
	case llvm.Br, llvm.Switch, llvm.IndirectBr, llvm.Invoke, llvm.Unreachable:
		// Parse the terminator instruction during the control flow analysis.
		bb.term = term
	default:
		return errutil.Newf("non-terminator instruction %q at end of basic block", prettyOpcode(opcode))
	}
	return nil
}
Esempio n. 18
0
// getBBName returns the name (or ID if unnamed) of a basic block.
func getBBName(v llvm.Value) (string, error) {
	if !v.IsBasicBlock() {
		return "", errutil.Newf("invalid value type; expected basic block, got %v", v.Type())
	}

	// Locate the name of a named basic block.
	if name := v.Name(); len(name) > 0 {
		return name, nil
	}

	// Locate the ID of an unnamed basic block by parsing the value dump in
	// search for its basic block label.
	//
	// Example value dump:
	//    0:
	//      br i1 true, label %1, label %2
	//
	// Each basic block is expected to have a label, which requires the
	// "unnamed.patch" to be applied to the llvm.org/llvm/bindings/go/llvm code
	// base.
	s, err := hackDump(v)
	if err != nil {
		return "", errutil.Err(err)
	}
	tokens := lexer.ParseString(s)
	if len(tokens) < 1 {
		return "", errutil.Newf("unable to locate basic block label in %q", s)
	}
	tok := tokens[0]
	if tok.Kind != token.Label {
		return "", errutil.Newf("invalid token; expected %v, got %v", token.Label, tok.Kind)
	}
	return tok.Val, nil
}
Esempio n. 19
0
func (a llvmAttribute) Apply(v llvm.Value) {
	if !v.IsAFunction().IsNil() {
		v.AddFunctionAttr(llvm.Attribute(a))
	} else {
		v.AddAttribute(llvm.Attribute(a))
	}
}
Esempio n. 20
0
func (c *compiler) addCommonFunctionAttrs(fn llvm.Value) {
	fn.AddTargetDependentFunctionAttr("disable-tail-calls", "true")
	fn.AddTargetDependentFunctionAttr("split-stack", "")
	if attr := c.SanitizerAttribute; attr != 0 {
		fn.AddFunctionAttr(attr)
	}
}
Esempio n. 21
0
// getBrCond parses the provided branch instruction and returns its condition.
//
// Syntax:
//    br i1 <cond>, label <target_true>, label <target_false>
func getBrCond(term llvm.Value) (cond ast.Expr, targetTrue, targetFalse string, err error) {
	// Parse and validate tokens.
	tokens, err := getTokens(term)
	if err != nil {
		return nil, "", "", err
	}
	if len(tokens) != 10 {
		// TODO: Remove debug output.
		term.Dump()
		return nil, "", "", errutil.Newf("unable to parse conditional branch instruction; expected 10 tokens, got %d", len(tokens))
	}

	// Create and return the condition.
	switch tok := tokens[2]; tok.Kind {
	case lltoken.KwTrue, lltoken.KwFalse, lltoken.LocalVar, lltoken.LocalID:
		//    true
		//    false
		//    %foo
		//    %42
		ident, err := getIdent(tok)
		if err != nil {
			return nil, "", "", errutil.Err(err)
		}
		return ident, tokens[5].Val, tokens[8].Val, nil
	case lltoken.Int:
		//    1
		//    0
		switch tok.Val {
		case "0":
			return newIdent("false"), tokens[5].Val, tokens[8].Val, nil
		case "1":
			return newIdent("true"), tokens[5].Val, tokens[8].Val, nil
		default:
			return nil, "", "", errutil.Newf("invalid integer value; expected boolean, got %q", tok.Val)
		}
	default:
		return nil, "", "", errutil.Newf("support for LLVM IR token kind %v not yet implemented", tok.Kind)
	}
}
Esempio n. 22
0
File: debug.go Progetto: hinike/llgo
// Declare creates an llvm.dbg.declare call for the specified function
// parameter or local variable.
func (d *DIBuilder) Declare(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) {
	tag := tagAutoVariable
	if paramIndex >= 0 {
		tag = tagArgVariable
	}
	var diFile llvm.Value
	var line int
	if file := d.fset.File(v.Pos()); file != nil {
		line = file.Line(v.Pos())
		diFile = d.getFile(file)
	}
	localVar := d.builder.CreateLocalVariable(d.scope(), llvm.DILocalVariable{
		Tag:   tag,
		Name:  llv.Name(),
		File:  diFile,
		Line:  line,
		ArgNo: paramIndex + 1,
		Type:  d.DIType(v.Type()),
	})
	expr := d.builder.CreateExpression(nil)
	d.builder.InsertDeclareAtEnd(llv, localVar, expr, b.GetInsertBlock())
}
Esempio n. 23
0
func (c *Codegen) generateCall(node *parser.CallExprNode, obj llvm.Value) llvm.Value {
	fn, args := c.getFunction(node.Function)

	if !obj.IsNil() {
		args = append([]llvm.Value{obj}, args...)
	}

	for i, arg := range node.Arguments {
		expr := c.generateExpression(arg)
		if fn.Type().ElementType().ParamTypesCount() > i {
			expr = c.convert(expr, fn.Type().ElementType().ParamTypes()[i])
		}

		//Unbox arguments for C functions
		if fn.BasicBlocksCount() == 0 {
			expr = c.unbox(expr)
		}

		args = append(args, expr)
	}

	return c.builder.CreateCall(fn, args, "")
}
Esempio n. 24
0
func (a nameAttribute) Apply(v llvm.Value) {
	if !v.IsAFunction().IsNil() {
		name := string(a)
		curr := v.GlobalParent().NamedFunction(name)
		if !curr.IsNil() && curr != v {
			if curr.BasicBlocksCount() != 0 {
				panic(fmt.Errorf("Want to take the name %s from a function that has a body!", name))
			}
			curr.SetName(name + "_llgo_replaced")
			curr.ReplaceAllUsesWith(llvm.ConstBitCast(v, curr.Type()))
		}
		v.SetName(name)
	} else {
		v.SetName(string(a))
	}
}
Esempio n. 25
0
// parseRetInst converts the provided LLVM IR ret instruction into an equivalent
// Go return statement.
//
// Syntax:
//    ret void
//    ret <type> <val>
func parseRetInst(inst llvm.Value) (*ast.ReturnStmt, error) {
	// TODO: Make more robust by using proper parsing instead of relying on
	// tokens. The current approach is used for a proof of concept and would fail
	// for composite literals. This TODO applies to the use of tokens in all
	// functions.

	// Parse and validate tokens.
	tokens, err := getTokens(inst)
	if err != nil {
		return nil, err
	}
	if len(tokens) < 4 {
		// TODO: Remove debug output.
		inst.Dump()
		return nil, errutil.Newf("unable to parse return instruction; expected >= 4 tokens, got %d", len(tokens))
	}
	typ := tokens[1]
	if typ.Kind != lltoken.Type {
		return nil, errutil.Newf(`invalid return instruction; expected type token, got %q`, typ)
	}

	// Create and return a void return statement.
	if typ.Val == "void" {
		return &ast.ReturnStmt{}, nil
	}

	// Create and return a return statement.
	val, err := parseOperand(inst.Operand(0))
	if err != nil {
		return nil, errutil.Err(err)
	}

	ret := &ast.ReturnStmt{
		Results: []ast.Expr{val},
	}
	return ret, nil
}
Esempio n. 26
0
// parsePHIInst converts the provided LLVM IR phi instruction into an equivalent
// variable definition mapping.
//
// Syntax:
//    %foo = phi i32 [ 42, %2 ], [ %bar, %3 ]
func parsePHIInst(inst llvm.Value) (ident string, defs []*definition, err error) {
	// Parse result.
	result, err := getResult(inst)
	if err != nil {
		return "", nil, errutil.Err(err)
	}
	ident = result.(*ast.Ident).Name

	// Parse and validate tokens.
	tokens, err := getTokens(inst)
	if err != nil {
		return "", nil, errutil.Err(err)
	}
	if len(tokens) < 10 {
		return "", nil, errutil.Newf("unable to parse PHI instruction; expected >= 10 tokens, got %d", len(tokens))
	}

	// Parse operands.
	for i := 0; i < inst.OperandsCount(); i++ {
		// Parse variable definition expression.
		expr, err := parseOperand(inst.Operand(i))
		if err != nil {
			return "", nil, errutil.Err(err)
		}

		// Parse source basic block.
		bbTok := tokens[7+i*6]
		if bbTok.Kind != lltoken.LocalID {
			return "", nil, errutil.Newf("invalid operand token, expected LocalID, got %v", bbTok.Kind)
		}
		def := &definition{bb: bbTok.Val, expr: expr}
		defs = append(defs, def)
	}

	return ident, defs, nil
}
Esempio n. 27
0
func (c *Codegen) generateComparisonBinaryExpr(left, right llvm.Value, op string) llvm.Value {
	t := c.getUnderlyingType(left.Type())
	if t == PRIMITIVE_TYPES["float"] {
		return c.builder.CreateFCmp(floatPredicates[op], left, right, "")
	} else if t == PRIMITIVE_TYPES["int"] || op == "==" || op == "!=" {
		log.Println("Left:", left.Type(), "Right:", right.Type())
		return c.builder.CreateICmp(intPredicates[op], left, right, "")
	}

	return null
}
Esempio n. 28
0
// parseInst converts the provided LLVM IR instruction into an equivalent Go AST
// node (a statement).
func parseInst(inst llvm.Value) (ast.Stmt, error) {
	// TODO: Remove debug output.
	if flagVerbose {
		fmt.Println("parseInst:")
		fmt.Println("   nops:", inst.OperandsCount())
		inst.Dump()
		fmt.Println()
	}

	// Assignment operation.
	//    %foo = ...
	opcode := inst.InstructionOpcode()
	if _, err := getResult(inst); err == nil {
		// Binary Operations
		switch opcode {
		case llvm.Add, llvm.FAdd:
			return parseBinOp(inst, token.ADD)
		case llvm.Sub, llvm.FSub:
			return parseBinOp(inst, token.SUB)
		case llvm.Mul, llvm.FMul:
			return parseBinOp(inst, token.MUL)
		case llvm.UDiv, llvm.SDiv, llvm.FDiv:
			// TODO: Handle signed and unsigned div separately.
			return parseBinOp(inst, token.QUO)
		case llvm.URem, llvm.SRem, llvm.FRem:
			// TODO: Handle signed and unsigned mod separately.
			return parseBinOp(inst, token.REM)

		// Bitwise Binary Operations
		case llvm.Shl:
			return parseBinOp(inst, token.SHL)
		case llvm.LShr, llvm.AShr:
			// TODO: Handle logical and arithmetic shift right separately.
			return parseBinOp(inst, token.SHR)
		case llvm.And:
			return parseBinOp(inst, token.AND)
		case llvm.Or:
			return parseBinOp(inst, token.OR)
		case llvm.Xor:
			return parseBinOp(inst, token.XOR)

		// Other Operators
		case llvm.ICmp, llvm.FCmp:
			pred, err := getCmpPred(inst)
			if err != nil {
				return nil, errutil.Err(err)
			}
			return parseBinOp(inst, pred)
		}
	}

	return nil, errutil.Newf("support for LLVM IR instruction %q not yet implemented", prettyOpcode(opcode))
}
Esempio n. 29
0
File: ssa.go Progetto: hinike/llgo
// bridgeRecoverFunc creates a function that may call recover(), and creates
// a call to it from the current frame. The created function will be called
// with a boolean parameter that indicates whether it may call recover().
//
// The created function will have the same name as the current frame's function
// with "$recover" appended, having the same return types and parameters with
// an additional boolean parameter appended.
//
// A new frame will be returned for the newly created function.
func (fr *frame) bridgeRecoverFunc(llfn llvm.Value, fti functionTypeInfo) *frame {
	// The bridging function must not be inlined, or the return address
	// may not correspond to the source function.
	llfn.AddFunctionAttr(llvm.NoInlineAttribute)

	// Call __go_can_recover, passing in the function's return address.
	entry := llvm.AddBasicBlock(llfn, "entry")
	fr.builder.SetInsertPointAtEnd(entry)
	canRecover := fr.runtime.canRecover.call(fr, fr.returnAddress(0))[0]
	returnType := fti.functionType.ReturnType()
	argTypes := fti.functionType.ParamTypes()
	argTypes = append(argTypes, canRecover.Type())

	// Create and call the $recover function.
	ftiRecover := fti
	ftiRecover.functionType = llvm.FunctionType(returnType, argTypes, false)
	llfnRecover := ftiRecover.declare(fr.module.Module, llfn.Name()+"$recover")
	fr.addCommonFunctionAttrs(llfnRecover)
	llfnRecover.SetLinkage(llvm.InternalLinkage)
	args := make([]llvm.Value, len(argTypes)-1, len(argTypes))
	for i := range args {
		args[i] = llfn.Param(i)
	}
	args = append(args, canRecover)
	result := fr.builder.CreateCall(llfnRecover, args, "")
	if returnType.TypeKind() == llvm.VoidTypeKind {
		fr.builder.CreateRetVoid()
	} else {
		fr.builder.CreateRet(result)
	}

	// The $recover function must condition calls to __go_recover on
	// the result of __go_can_recover passed in as an argument.
	fr = newFrame(fr.unit, llfnRecover)
	fr.retInf = ftiRecover.retInf
	fr.canRecover = fr.function.Param(len(argTypes) - 1)
	return fr
}
Esempio n. 30
0
File: cabi.go Progetto: hinike/llgo
func (ai *indirectArgInfo) encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, args []llvm.Value, val llvm.Value) {
	alloca := allocaBuilder.CreateAlloca(val.Type(), "")
	builder.CreateStore(val, alloca)
	args[ai.argOffset] = alloca
}