Exemple #1
0
// expand attempts to locate and return the definition of the provided
// identifier expression. The assignment statement defining the identifier is
// removed from the statement list of the basic block.
func expand(bb BasicBlock, ident ast.Expr) (ast.Expr, error) {
	id, ok := ident.(*ast.Ident)
	if !ok {
		return nil, errutil.Newf("unable to expand expression; expected identifier, got %T", ident)
	}
	var stmts []ast.Stmt
	var expr ast.Expr
	for _, stmt := range bb.Stmts() {
		switch stmt := stmt.(type) {
		case *ast.AssignStmt:
			if sameIdent(stmt.Lhs, id) {
				if len(stmt.Rhs) != 1 {
					return nil, errutil.Newf("invalid right-hand side; expected length 1, got %d", len(stmt.Rhs))
				}
				expr = stmt.Rhs[0]
				// TODO: Verify if the identifier is used by any other statement or
				// terminator instruction before removing it; this includes the use
				// within other basic blocks.

				// Remove the variable definition of the right-hand side expression
				// by not appending the assignment statement to the statement list.
				continue
			}
		}
		stmts = append(stmts, stmt)
	}
	if expr == nil {
		return nil, errutil.Newf("unable to expand definition of identifier %q", id.Name)
	}
	bb.SetStmts(stmts)
	return expr, nil
}
Exemple #2
0
Fichier : irx.go Projet : llir/llvm
// NewGetElementPtrInst returns a new getelementptr instruction based on the
// given element type, address and element indices.
func NewGetElementPtrInst(elem, srcAddrType, srcAddr, elemIndices interface{}) (*instruction.GetElementPtr, error) {
	if elem, ok := elem.(types.Type); ok {
		srcAddr, err := NewValue(srcAddrType, srcAddr)
		if err != nil {
			return nil, errutil.Err(err)
		}
		var indices []value.Value
		switch elemIndices := elemIndices.(type) {
		case []value.Value:
			indices = elemIndices
		case nil:
		default:
			panic(fmt.Sprintf("support for element indices type %T not yet implemented", elemIndices))
		}
		// Validate that elem is of identical type as the element type of srcAddr.
		srcAddrType, ok := srcAddr.Type().(*types.Pointer)
		if !ok {
			return nil, errutil.Newf("invalid source address pointer type; expected *types.Pointer, got %T", srcAddr.Type())
		}
		if !types.Equal(elem, srcAddrType.Elem()) {
			return nil, errutil.Newf("type mismatch between element type (%v) and source address element type (%v)", elem, srcAddrType.Elem())
		}
		return instruction.NewGetElementPtr(srcAddr, indices)
	}
	return nil, errutil.Newf("invalid operand type; expected types.Type, got %T", elem)
}
Exemple #3
0
Fichier : irx.go Projet : llir/llvm
// NewBasicBlock returns a new basic block based on the given name, non-
// terminating instructions and terminator.
func NewBasicBlock(nameToken, insts, term interface{}) (*ir.BasicBlock, error) {
	// Get label name.
	var name string
	switch nameToken := nameToken.(type) {
	case *token.Token:
		// Strip ":" suffix.
		s, err := stripLabelSuffix(nameToken.Lit)
		if err != nil {
			return nil, errutil.Err(err)
		}
		name = s
	case nil:
		// Unnamed basic block.
	default:
		return nil, errutil.Newf("invalid basic block name type; expected *token.Token, got %T", nameToken)
	}

	if term, ok := term.(instruction.Terminator); ok {
		switch insts := insts.(type) {
		case []instruction.Instruction:
			block := ir.NewBasicBlock(name)
			block.SetInsts(insts)
			block.SetTerm(term)
			return block, nil
		case nil:
			block := ir.NewBasicBlock(name)
			block.SetTerm(term)
			return block, nil
		default:
			return nil, errutil.Newf("invalid non-terminating instructions type; expected []instruction.Instruction, got %T", insts)
		}
	}
	return nil, errutil.Newf("invalid terminator type; expected instruction.Terminator, got %T", term)
}
Exemple #4
0
// NewSubGraph returns a new subgraph based on graph with a dedicated entry and
// exit node. The entry and exit nodes are identified using the node "label"
// attribute, e.g.
//
//    digraph if {
//       A->B [label="true"]
//       A->C [label="false"]
//       B->C
//       A [label="entry"]
//       B
//       C [label="exit"]
//    }
func NewSubGraph(graph *dot.Graph) (*SubGraph, error) {
	sub := &SubGraph{Graph: graph}

	// Locate entry and exit nodes.
	var hasEntry, hasExit bool
	for _, node := range graph.Nodes.Nodes {
		label, ok := node.Attrs["label"]
		if !ok {
			continue
		}
		switch label {
		case "entry":
			if hasEntry {
				return nil, errutil.Newf(`redefinition of node with "entry" label; previous node %q, new node %q`, sub.entry, node.Name)
			}
			sub.entry = node.Name
			hasEntry = true
		case "exit":
			if hasExit {
				return nil, errutil.Newf(`redefinition of node with "exit" label; previous node %q, new node %q`, sub.exit, node.Name)
			}
			sub.exit = node.Name
			hasExit = true
		}
	}
	if !hasEntry {
		return nil, errutil.New(`unable to locate node with "entry" label`)
	}
	if !hasExit {
		return nil, errutil.New(`unable to locate node with "exit" label`)
	}

	return sub, nil
}
Exemple #5
0
// candidates locates node pair candidates for an isomorphism of sub in graph
// which starts at the entry node.
func candidates(graph *dot.Graph, entry string, sub *graphs.SubGraph) (*equation, error) {
	// Sanity checks.
	g, ok := graph.Nodes.Lookup[entry]
	if !ok {
		return nil, errutil.Newf("unable to locate entry node %q in graph", entry)
	}
	s, ok := sub.Nodes.Lookup[sub.Entry()]
	if !ok {
		panic(fmt.Sprintf("unable to locate entry node %q in sub", sub.Entry()))
	}
	if !isPotential(g, s, sub) {
		return nil, errutil.Newf("invalid entry node candidate %q; expected %d successors, got %d", g.Name, len(s.Succs), len(g.Succs))
	}

	// Locate candidate node pairs.
	eq := &equation{
		c: make(map[string]map[string]bool),
		m: make(map[string]string),
	}
	eq.findCandidates(g, s, sub)
	if len(eq.c) != len(sub.Nodes.Nodes) {
		return nil, errutil.Newf("incomplete candidate mapping; expected %d map entites, got %d", len(sub.Nodes.Nodes), len(eq.c))
	}

	return eq, nil
}
Exemple #6
0
// NewArrayType returns a new array type based on the given element type and
// length.
func NewArrayType(elem, lbracket, length, rbracket interface{}) (*ast.ArrayType, error) {
	len, ok := length.(int)
	if !ok {
		return nil, errutil.Newf("invalid array length type; %T", length)
	}

	var lbrack, rbrack int
	switch lbracket := lbracket.(type) {
	case *gocctoken.Token:
		lbrack = lbracket.Offset
	case int:
		lbrack = lbracket
	default:
		return nil, errutil.Newf("invalid left-bracket type; expectd *gocctoken.Token or int, got %T", lbracket)
	}
	switch rbracket := rbracket.(type) {
	case *gocctoken.Token:
		rbrack = rbracket.Offset
	case int:
		rbrack = rbracket
	default:
		return nil, errutil.Newf("invalid right-bracket type; expectd *gocctoken.Token or int, got %T", rbracket)
	}

	elemType, err := NewType(elem)
	if err != nil {
		return nil, errutil.Newf("invalid array element type; %v", err)
	}
	return &ast.ArrayType{Elem: elemType, Lbracket: lbrack, Len: len, Rbracket: rbrack}, nil
}
Exemple #7
0
// createListPrim creates a list primitive containing a slice of Go statements
// based on the identified subgraph, its node pair mapping and its basic blocks.
// The new control flow primitive conceptually represents a basic block with the
// given name.
//
// Contents of "list.dot":
//
//    digraph list {
//       entry [label="entry"]
//       exit [label="exit"]
//       entry->exit
//    }
func createListPrim(m map[string]string, bbs map[string]BasicBlock, newName string) (*primitive, error) {
	// Locate graph nodes.
	nameEntry, ok := m["entry"]
	if !ok {
		return nil, errutil.New(`unable to locate node pair for sub node "entry"`)
	}
	nameExit, ok := m["exit"]
	if !ok {
		return nil, errutil.New(`unable to locate node pair for sub node "exit"`)
	}
	bbEntry, ok := bbs[nameEntry]
	if !ok {
		return nil, errutil.Newf("unable to locate basic block %q", nameEntry)
	}
	bbExit, ok := bbs[nameExit]
	if !ok {
		return nil, errutil.Newf("unable to locate basic block %q", nameExit)
	}

	// Create and return new primitive.
	//
	//    entry
	//    exit
	stmts := append(bbEntry.Stmts(), bbExit.Stmts()...)
	prim := &primitive{
		name:  newName,
		stmts: stmts,
		term:  bbExit.Term(),
	}
	return prim, nil
}
Exemple #8
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
}
Exemple #9
0
Fichier : irx.go Projet : llir/llvm
// NewFunc returns a new function based on the given result type, function name,
// and function parameters.
func NewFunc(result, gname, params interface{}) (*ir.Function, error) {
	if result, ok := result.(types.Type); ok {
		name, err := getGlobalName(gname)
		if err != nil {
			return nil, errutil.Err(err)
		}
		var sig *types.Func
		switch params := params.(type) {
		case *Params:
			sig, err = types.NewFunc(result, params.params, params.variadic)
			if err != nil {
				return nil, errutil.Err(err)
			}
		case nil:
			sig, err = types.NewFunc(result, nil, false)
			if err != nil {
				return nil, errutil.Err(err)
			}
		default:
			return nil, errutil.Newf("invalid function parameters specifier type; expected *Params, got %T", params)
		}
		return ir.NewFunction(name, sig), nil
	}
	return nil, errutil.Newf("invalid function result type; expected types.Type, got %T", result)
}
Exemple #10
0
// getCmpPred parses the provided comparison instruction and returns a Go token
// equivalent of the comparison predicate.
//
// Syntax:
//    <result> = icmp <pred> <type> <op1>, <op2>
func getCmpPred(inst llvm.Value) (token.Token, error) {
	// Parse and validate tokens.
	tokens, err := getTokens(inst)
	if err != nil {
		return 0, errutil.Err(err)
	}
	if len(tokens) < 4 {
		return 0, errutil.Newf("unable to parse comparison instruction; expected >= 4 tokens, got %d", len(tokens))
	}

	// TODO: Handle signed and unsigned predicates separately.
	switch pred := tokens[3]; pred.Kind {
	// Int predicates.
	case lltoken.KwEq: // eq: equal
		return token.EQL, nil // ==
	case lltoken.KwNe: // ne: not equal
		return token.NEQ, nil // !=
	case lltoken.KwUgt: // ugt: unsigned greater than
		return token.GTR, nil // >
	case lltoken.KwUge: // uge: unsigned greater or equal
		return token.GEQ, nil // >=
	case lltoken.KwUlt: // ult: unsigned less than
		return token.LSS, nil // <
	case lltoken.KwUle: // ule: unsigned less or equal
		return token.LEQ, nil // <=
	case lltoken.KwSgt: // sgt: signed greater than
		return token.GTR, nil // >
	case lltoken.KwSge: // sge: signed greater or equal
		return token.GEQ, nil // >=
	case lltoken.KwSlt: // slt: signed less than
		return token.LSS, nil // <
	case lltoken.KwSle: // sle: signed less or equal
		return token.LEQ, nil // <=

	// Float predicates.
	case lltoken.KwOeq: // oeq: ordered and equal
		return token.EQL, nil // ==
	case lltoken.KwOgt: // ogt: ordered and greater than
		return token.GTR, nil // >
	case lltoken.KwOge: // oge: ordered and greater than or equal
		return token.GEQ, nil // >=
	case lltoken.KwOlt: // olt: ordered and less than
		return token.LSS, nil // <
	case lltoken.KwOle: // ole: ordered and less than or equal
		return token.LEQ, nil // <=
	case lltoken.KwOne: // one: ordered and not equal
		return token.NEQ, nil // !=
	case lltoken.KwOrd: // ord: ordered (no nans)
		return 0, errutil.Newf(`support for the floating point comparison predicate "ord" not yet implemented`)
	case lltoken.KwUeq: // ueq: unordered or equal
		return token.EQL, nil // ==
	case lltoken.KwUne: // une: unordered or not equal
		return token.NEQ, nil // !=
	case lltoken.KwUno: // uno: unordered (either nans)
		return 0, errutil.Newf(`support for the floating point comparison predicate "uno" not yet implemented`)

	default:
		return 0, errutil.Newf("invalid token; expected comparison predicate, got %q", pred)
	}
}
Exemple #11
0
Fichier : irx.go Projet : llir/llvm
// AppendIncoming appends inc to the incoming values list.
func AppendIncoming(list, inc interface{}) ([]*Incoming, error) {
	if list, ok := list.([]*Incoming); ok {
		if inc, ok := inc.(*Incoming); ok {
			return append(list, inc), nil
		}
		return nil, errutil.Newf("invalid incoming values list incoming value type; expected *Incoming, got %T", inc)
	}
	return nil, errutil.Newf("invalid incoming values list type; expected []*Incoming, got %T", list)
}
Exemple #12
0
Fichier : irx.go Projet : llir/llvm
// AppendValue appends val to the value list.
func AppendValue(list, val interface{}) ([]value.Value, error) {
	if list, ok := list.([]value.Value); ok {
		if val, ok := val.(value.Value); ok {
			return append(list, val), nil
		}
		return nil, errutil.Newf("invalid value list value type; expected value.Value, got %T", val)
	}
	return nil, errutil.Newf("invalid value list type; expected []value.Value, got %T", list)
}
Exemple #13
0
Fichier : irx.go Projet : llir/llvm
// AppendParam appends param to the function parameter list.
func AppendParam(list, param interface{}) ([]*types.Param, error) {
	if list, ok := list.([]*types.Param); ok {
		if param, ok := param.(*types.Param); ok {
			return append(list, param), nil
		}
		return nil, errutil.Newf("invalid function parameter list parameter type; expected *types.Param, got %T", param)
	}
	return nil, errutil.Newf("invalid function parameter list type; expected []*types.Param, got %T", list)
}
Exemple #14
0
// parseFunc parses the given function and attempts to construct an equivalent
// Go function declaration AST node.
func parseFunc(graph *dot.Graph, module llvm.Module, funcName string, hprims []*xprimitive.Primitive) (*ast.FuncDecl, error) {
	llFunc := module.NamedFunction(funcName)
	if llFunc.IsNil() {
		return nil, errutil.Newf("unable to locate function %q", funcName)
	}
	if llFunc.IsDeclaration() {
		return nil, errutil.Newf("unable to create AST for %q; expected function definition, got function declaration (e.g. no body)", funcName)
	}

	// Parse each basic block.
	bbs := make(map[string]BasicBlock)
	for _, llBB := range llFunc.BasicBlocks() {
		bb, err := parseBasicBlock(llBB)
		if err != nil {
			return nil, err
		}
		bbs[bb.Name()] = bb
		if flagVerbose && !flagQuiet {
			printBB(bb)
		}
	}

	// Replace PHI instructions with assignment statements in the appropriate
	// basic blocks.
	for _, bb := range bbs {
		block, ok := bb.(*basicBlock)
		if !ok {
			return nil, errutil.Newf("invalid basic block type; expected *basicBlock, got %T", bb)
		}
		for ident, defs := range block.phis {
			for _, def := range defs {
				assign := &ast.AssignStmt{
					Lhs: []ast.Expr{newIdent(ident)},
					Tok: token.ASSIGN,
					Rhs: []ast.Expr{def.expr},
				}
				bbSrc := bbs[def.bb]
				stmts := bbSrc.Stmts()
				stmts = append(stmts, assign)
				bbSrc.SetStmts(stmts)
			}
		}
	}

	// Perform control flow analysis.
	body, err := restructure(graph, bbs, hprims)
	if err != nil {
		return nil, errutil.Err(err)
	}
	sig := &ast.FuncType{
		Params: &ast.FieldList{},
	}
	if funcName != "main" {
		// TODO: Implement parsing of function signature.
	}
	return createFunc(funcName, sig, body)
}
Exemple #15
0
Fichier : irx.go Projet : llir/llvm
// AppendTopLevelDecl appends decl to the top-level declaration list.
func AppendTopLevelDecl(list, decl interface{}) ([]TopLevelDecl, error) {
	if list, ok := list.([]TopLevelDecl); ok {
		if decl, ok := decl.(TopLevelDecl); ok {
			return append(list, decl), nil
		}
		return nil, errutil.Newf("invalid top-level declaration list top-level declaration type; expected TopLevelDecl, got %T", decl)
	}
	return nil, errutil.Newf("invalid top-level declaration list type; expected []TopLevelDecl, got %T", list)
}
Exemple #16
0
Fichier : irx.go Projet : llir/llvm
// AppendBasicBlock appends block to the basic block list.
func AppendBasicBlock(list, block interface{}) ([]*ir.BasicBlock, error) {
	if list, ok := list.([]*ir.BasicBlock); ok {
		if block, ok := block.(*ir.BasicBlock); ok {
			return append(list, block), nil
		}
		return nil, errutil.Newf("invalid basic block list basic block type; expected *ir.BasicBlock, got %T", block)
	}
	return nil, errutil.Newf("invalid basic block list type; expected []*ir.BasicBlock, got %T", list)
}
Exemple #17
0
Fichier : irx.go Projet : llir/llvm
// AppendInstruction appends inst to the instruction list.
func AppendInstruction(list, inst interface{}) ([]instruction.Instruction, error) {
	if list, ok := list.([]instruction.Instruction); ok {
		if inst, ok := inst.(instruction.Instruction); ok {
			return append(list, inst), nil
		}
		return nil, errutil.Newf("invalid instruction list instruction type; expected instruction.Instruction, got %T", inst)
	}
	return nil, errutil.Newf("invalid instruction list type; expected []instruction.Instruction, got %T", list)
}
Exemple #18
0
Fichier : irx.go Projet : llir/llvm
// AppendField appends typ to the structure field list.
func AppendField(list, typ interface{}) ([]types.Type, error) {
	if list, ok := list.([]types.Type); ok {
		if typ, ok := typ.(types.Type); ok {
			return append(list, typ), nil
		}
		return nil, errutil.Newf("invalid structure field list field type; expected types.Type, got %T", typ)
	}
	return nil, errutil.Newf("invalid structure field list type; expected []types.Type, got %T", list)
}
Exemple #19
0
// createPostLoopPrim creates a post-test loop primitive based on the identified
// subgraph, its node pair mapping and its basic blocks. The new control flow
// primitive conceptually represents a basic block with the given name.
//
// Contents of "post_loop.dot":
//
//    digraph post_loop {
//       cond [label="entry"]
//       exit [label="exit"]
//       cond->cond [label="true"]
//       cond->exit [label="false"]
//    }
func createPostLoopPrim(m map[string]string, bbs map[string]BasicBlock, newName string) (*primitive, error) {
	// Locate graph nodes.
	nameCond, ok := m["cond"]
	if !ok {
		return nil, errutil.New(`unable to locate node pair for sub node "cond"`)
	}
	nameExit, ok := m["exit"]
	if !ok {
		return nil, errutil.New(`unable to locate node pair for sub node "exit"`)
	}
	bbCond, ok := bbs[nameCond]
	if !ok {
		return nil, errutil.Newf("unable to locate basic block %q", nameCond)
	}
	bbExit, ok := bbs[nameExit]
	if !ok {
		return nil, errutil.Newf("unable to locate basic block %q", nameExit)
	}

	// Create and return new primitive.
	//
	//    for {
	//       cond_stmts
	//       if !cond {
	//          break
	//       }
	//    }
	//    exit

	// Create if-statement.
	cond, _, _, err := getBrCond(bbCond.Term())
	if err != nil {
		return nil, errutil.Err(err)
	}
	ifStmt := &ast.IfStmt{
		Cond: &ast.UnaryExpr{Op: token.NOT, X: cond}, // negate condition
		Body: &ast.BlockStmt{List: []ast.Stmt{&ast.BranchStmt{Tok: token.BREAK}}},
	}

	// Create for-loop.
	body := bbCond.Stmts()
	body = append(body, ifStmt)
	forStmt := &ast.ForStmt{
		Body: &ast.BlockStmt{List: body},
	}

	// Create primitive.
	stmts := []ast.Stmt{forStmt}
	stmts = append(stmts, bbExit.Stmts()...)
	prim := &primitive{
		name:  newName,
		stmts: stmts,
		term:  bbExit.Term(),
	}
	return prim, nil
}
Exemple #20
0
// AppendBlockItem appends item to the block item list, based on the following
// production rule.
//
//    BlockItemList
//       : BlockItemList BlockItem
//    ;
func AppendBlockItem(list, item interface{}) ([]ast.BlockItem, error) {
	lst, ok := list.([]ast.BlockItem)
	if !ok {
		return nil, errutil.Newf("invalid block item list type; expected []ast.BlockItem, got %T", list)
	}
	if item, ok := item.(ast.BlockItem); ok {
		return append(lst, item), nil
	}
	return nil, errutil.Newf("invalid block item list block item type; expected ast.BlockItem, got %T", item)
}
Exemple #21
0
// AppendDecl appends decl to the declaration list, based on the following
// production rule.
//
//    DeclList
//       : DeclList Decl
//    ;
func AppendDecl(list, decl interface{}) ([]ast.Decl, error) {
	lst, ok := list.([]ast.Decl)
	if !ok {
		return nil, errutil.Newf("invalid declaration list type; expected []ast.Decl, got %T", list)
	}
	if decl, ok := decl.(ast.Decl); ok {
		return append(lst, decl), nil
	}
	return nil, errutil.Newf("invalid declaration list declaration type; expected ast.Decl, got %T", decl)
}
Exemple #22
0
// AppendParam appends parameter to the parameter list, based on the following
// production rule.
//
//    ParamList
//       : ParamList "," Param
//    ;
func AppendParam(list, param interface{}) ([]*ast.VarDecl, error) {
	lst, ok := list.([]*ast.VarDecl)
	if !ok {
		return nil, errutil.Newf("invalid parameter list type; expected []*ast.VarDecl, got %T", list)
	}
	if param, ok := param.(*ast.VarDecl); ok {
		return append(lst, param), nil
	}
	return nil, errutil.Newf("invalid parameter list parameter type; expected *ast.VarDecl, got %T", param)
}
Exemple #23
0
// AppendExpr appends x to the expression list, based on the following
// production rule.
//
//    ExprList
//       : ExprList "," Expr
//    ;
func AppendExpr(list, x interface{}) ([]ast.Expr, error) {
	lst, ok := list.([]ast.Expr)
	if !ok {
		return nil, errutil.Newf("invalid expression list type; expected []ast.Expr, got %T", list)
	}
	if x, ok := x.(ast.Expr); ok {
		return append(lst, x), nil
	}
	return nil, errutil.Newf("invalid expression list expression type; expected ast.Expr, got %T", x)
}
Exemple #24
0
// createIfPrim creates an if-statement primitive based on the identified
// subgraph, its node pair mapping and its basic blocks. The new control flow
// primitive conceptually represents a basic block with the given name.
//
// Contents of "if.dot":
//
//    digraph if {
//       cond [label="entry"]
//       body
//       exit [label="exit"]
//       cond->body [label="true"]
//       cond->exit [label="false"]
//       body->exit
//    }
func createIfPrim(m map[string]string, bbs map[string]BasicBlock, newName string) (*primitive, error) {
	// Locate graph nodes.
	nameCond, ok := m["cond"]
	if !ok {
		return nil, errutil.New(`unable to locate node pair for sub node "cond"`)
	}
	nameBody, ok := m["body"]
	if !ok {
		return nil, errutil.New(`unable to locate node pair for sub node "body"`)
	}
	nameExit, ok := m["exit"]
	if !ok {
		return nil, errutil.New(`unable to locate node pair for sub node "exit"`)
	}
	bbCond, ok := bbs[nameCond]
	if !ok {
		return nil, errutil.Newf("unable to locate basic block %q", nameCond)
	}
	bbBody, ok := bbs[nameBody]
	if !ok {
		return nil, errutil.Newf("unable to locate basic block %q", nameBody)
	}
	bbExit, ok := bbs[nameExit]
	if !ok {
		return nil, errutil.Newf("unable to locate basic block %q", nameExit)
	}

	// Create and return new primitive.
	//
	//    cond_stmts
	//    if cond {
	//       body
	//    }
	//    exit

	// Create if-statement.
	cond, _, _, err := getBrCond(bbCond.Term())
	if err != nil {
		return nil, errutil.Err(err)
	}
	ifStmt := &ast.IfStmt{
		Cond: cond,
		Body: &ast.BlockStmt{List: bbBody.Stmts()},
	}

	// Create primitive.
	stmts := append(bbCond.Stmts(), ifStmt)
	stmts = append(stmts, bbExit.Stmts()...)
	prim := &primitive{
		name:  newName,
		stmts: stmts,
		term:  bbExit.Term(),
	}
	return prim, nil
}
Exemple #25
0
// NewSelect returns a new select instruction based on the given selection
// condition, and operands.
//
// Pre-condition: cond is of boolean or boolean vector type. x and y are of
// identical types.
func NewSelect(cond, x, y value.Value) (*Select, error) {
	// Validate that cond is of boolean or boolean vector type.
	if !types.IsBools(cond.Type()) {
		return nil, errutil.Newf("invalid selection condition type; expected boolean or boolean vector, got %v", cond.Type())
	}
	// Validate that x and y are of identical types.
	if !types.Equal(x.Type(), y.Type()) {
		return nil, errutil.Newf("type mismatch between x (%v) and y (%v)", x.Type(), y.Type())
	}
	return &Select{cond: cond, x: x, y: y}, nil
}
Exemple #26
0
// unquote interprets s as a double-quoted LLVM IR string literal, returning the
// string value that s quotes.
func unquote(s string) (string, error) {
	if !strings.HasPrefix(s, `"`) {
		return "", errutil.Newf(`invalid prefix of quoted string %q; expected '"'`, s)
	}
	s = s[1:]
	if !strings.HasSuffix(s, `"`) {
		return "", errutil.Newf(`invalid suffix of quoted string %q; expected '"'`, s)
	}
	s = s[:len(s)-1]
	return enc.Unescape(s), nil
}
Exemple #27
0
// NewArrayDecl returns a new array declaration node, based on the following
// production rule.
//
//    ArrayDecl
//       : BasicType ident "[" int_lit "]"
//    ;
func NewArrayDecl(elem, name, lbracket, length, rbracket interface{}) (*ast.VarDecl, error) {
	typ, err := NewArrayType(elem, lbracket, length, rbracket)
	if err != nil {
		return nil, errutil.Newf("invalid array type; %v", err)
	}
	ident, err := NewIdent(name)
	if err != nil {
		return nil, errutil.Newf("invalid array declaration identifier; %v", err)
	}
	return &ast.VarDecl{VarType: typ, VarName: ident}, nil
}
Exemple #28
0
// NewScalarDecl returns a new scalar declaration node, based on the following
// production rule.
//
//    ScalarDecl
//       : TypeName ident
//    ;
func NewScalarDecl(typ, name interface{}) (*ast.VarDecl, error) {
	scalarType, err := NewType(typ)
	if err != nil {
		return nil, errutil.Newf("invalid scalar type; %v", err)
	}
	ident, err := NewIdent(name)
	if err != nil {
		return nil, errutil.Newf("invalid scalar declaration identifier; %v", err)
	}
	return &ast.VarDecl{VarType: scalarType, VarName: ident}, nil
}
Exemple #29
0
Fichier : irx.go Projet : llir/llvm
// NewFuncDef returns a new function definition based on the given function
// header and body.
func NewFuncDef(fn, blocks interface{}) (*ir.Function, error) {
	if fn, ok := fn.(*ir.Function); ok {
		if blocks, ok := blocks.([]*ir.BasicBlock); ok {
			if err := fn.SetBlocks(blocks); err != nil {
				return nil, errutil.Err(err)
			}
			return fn, nil
		}
		return nil, errutil.Newf("invalid function body type; expected []*ir.BasicBlock, got %T", blocks)
	}
	return nil, errutil.Newf("invalid function header type; expected *ir.Function, got %T", fn)
}
Exemple #30
0
// NewStore returns a new store instruction based on the given source value and
// destination address.
//
// Pre-condition:
//    1. dstAddr is of pointer type
//    2. src is of identical type as the element type of dstAddr
func NewStore(src, dstAddr value.Value) (*Store, error) {
	// Validate that dstAddr is of pointer type.
	dstAddrType, ok := dstAddr.Type().(*types.Pointer)
	if !ok {
		return nil, errutil.Newf("invalid destination address pointer type; expected *types.Pointer, got %T", dstAddr.Type())
	}
	// Validate that src is of identical type as the element type of dstAddr.
	if !types.Equal(src.Type(), dstAddrType.Elem()) {
		return nil, errutil.Newf("type mismatch between source value (%v) and destination address element type (%v)", src.Type(), dstAddrType.Elem())
	}
	return &Store{src: src, dstAddr: dstAddr}, nil
}