コード例 #1
0
ファイル: instruction.go プロジェクト: decomp/decomp
// 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
}
コード例 #2
0
ファイル: instruction.go プロジェクト: decomp/decomp
// 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
}
コード例 #3
0
ファイル: instruction.go プロジェクト: decomp/decomp
// 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
}
コード例 #4
0
ファイル: ssa.go プロジェクト: hinike/llgo
// If val is a constant and addr refers to a global variable which is defined in
// this module or an element thereof, simulate the effect of storing val at addr
// in the global variable's initializer and return true, otherwise return false.
// Precondition: we are compiling the init function.
func (fr *frame) maybeStoreInInitializer(val, addr llvm.Value) bool {
	if val.IsAConstant().IsNil() {
		return false
	}

	if !addr.IsAConstantExpr().IsNil() && addr.OperandsCount() >= 2 &&
		// TODO(pcc): Explicitly check that this is a constant GEP.
		// I don't think there are any other kinds of constantexpr which
		// satisfy the conditions we test for here, so this is probably safe.
		!addr.Operand(0).IsAGlobalVariable().IsNil() &&
		addr.Operand(1).IsNull() {
		gv := addr.Operand(0)
		globalInit, ok := fr.globalInits[gv]
		if !ok {
			return false
		}
		indices := make([]uint32, addr.OperandsCount()-2)
		for i := range indices {
			op := addr.Operand(i + 2)
			if op.IsAConstantInt().IsNil() {
				return false
			}
			indices[i] = uint32(op.ZExtValue())
		}
		globalInit.update(gv.Type().ElementType(), indices, val)
		return true
	} else if !addr.IsAGlobalVariable().IsNil() {
		if globalInit, ok := fr.globalInits[addr]; ok {
			globalInit.update(addr.Type().ElementType(), nil, val)
			return true
		}
		return false
	} else {
		return false
	}
}