// 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)) }
// 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 }
// 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 } }