diff --git a/mlir/include/mlir/IR/Builders.h b/mlir/include/mlir/IR/Builders.h index 3cc8227c44de..a545fe1be646 100644 --- a/mlir/include/mlir/IR/Builders.h +++ b/mlir/include/mlir/IR/Builders.h @@ -18,7 +18,6 @@ #ifndef MLIR_IR_BUILDERS_H #define MLIR_IR_BUILDERS_H -#include "mlir/IR/Attributes.h" #include "mlir/IR/CFGFunction.h" #include "mlir/IR/MLFunction.h" #include "mlir/IR/Statements.h" @@ -26,6 +25,9 @@ namespace mlir { class MLIRContext; class Module; +class UnknownLoc; +class UniquedFilename; +class FileLineColLoc; class Type; class PrimitiveType; class IntegerType; @@ -59,6 +61,12 @@ public: Identifier getIdentifier(StringRef str); Module *createModule(); + // Locations. + UnknownLoc *getUnknownLoc(); + UniquedFilename getUniquedFilename(StringRef filename); + FileLineColLoc *getFileLineColLoc(UniquedFilename filename, unsigned line, + unsigned column); + // Types. FloatType *getBF16Type(); FloatType *getF16Type(); @@ -185,7 +193,7 @@ public: /// Create operation of specific op type at the current insertion point. template - OpPointer create(Attribute *location, Args... args) { + OpPointer create(Location *location, Args... args) { OperationState state(getContext(), location, OpTy::getOperationName()); OpTy::build(this, &state, args...); auto *inst = createOperation(state); @@ -202,16 +210,16 @@ public: // Terminators. - ReturnInst *createReturn(Attribute *location, ArrayRef operands) { + ReturnInst *createReturn(Location *location, ArrayRef operands) { return insertTerminator(ReturnInst::create(location, operands)); } - BranchInst *createBranch(Attribute *location, BasicBlock *dest, + BranchInst *createBranch(Location *location, BasicBlock *dest, ArrayRef operands = {}) { return insertTerminator(BranchInst::create(location, dest, operands)); } - CondBranchInst *createCondBranch(Attribute *location, CFGValue *condition, + CondBranchInst *createCondBranch(Location *location, CFGValue *condition, BasicBlock *trueDest, BasicBlock *falseDest) { return insertTerminator( @@ -290,7 +298,7 @@ public: /// Create operation of specific op type at the current insertion point. template - OpPointer create(Attribute *location, Args... args) { + OpPointer create(Location *location, Args... args) { OperationState state(getContext(), location, OpTy::getOperationName()); OpTy::build(this, &state, args...); auto *stmt = createOperation(state); @@ -311,15 +319,12 @@ public: return cloneStmt; } - /// Create a 'for' statement with bounds that may involve MLValue operands. - /// When step is not specified, it is set to 1. - ForStmt *createFor(Attribute *location, ArrayRef lbOperands, + // Creates for statement. When step is not specified, it is set to 1. + ForStmt *createFor(Location *location, ArrayRef lbOperands, AffineMap *lbMap, ArrayRef ubOperands, AffineMap *ubMap, int64_t step = 1); - /// Create if statement. - /// TODO: pass operands. - IfStmt *createIf(Attribute *location, IntegerSet *condition); + IfStmt *createIf(Location *location, IntegerSet *condition); private: StmtBlock *block = nullptr; diff --git a/mlir/include/mlir/IR/Instructions.h b/mlir/include/mlir/IR/Instructions.h index ad0cb057c448..1f75241ace44 100644 --- a/mlir/include/mlir/IR/Instructions.h +++ b/mlir/include/mlir/IR/Instructions.h @@ -49,9 +49,8 @@ public: /// Return the context this operation is associated with. MLIRContext *getContext() const; - /// The source location the operation was defined or derived from. Note that - /// it is possible for this pointer to be null. - Attribute *getLoc() const { return location; } + /// The source location the operation was defined or derived from. + Location *getLoc() const { return location; } /// Return the BasicBlock containing this instruction. BasicBlock *getBlock() const { return block; } @@ -138,8 +137,9 @@ public: void emitNote(const Twine &message) const; protected: - Instruction(Kind kind, Attribute *location) - : kind(kind), location(location) {} + Instruction(Kind kind, Location *location) : kind(kind), location(location) { + assert(location && "location can never be null"); + } // Instructions are deleted through the destroy() member because this class // does not have a virtual destructor. A vtable would bloat the size of @@ -153,7 +153,7 @@ private: /// This holds information about the source location the operation was defined /// or derived from. - Attribute *location; + Location *location; friend struct llvm::ilist_traits; friend class BasicBlock; @@ -172,8 +172,8 @@ class OperationInst final public llvm::ilist_node_with_parent, private llvm::TrailingObjects { public: - /// Create a new OperationInst with the specific fields. - static OperationInst *create(Attribute *location, Identifier name, + /// Create a new OperationInst with the specified fields. + static OperationInst *create(Location *location, Identifier name, ArrayRef operands, ArrayRef resultTypes, ArrayRef attributes, @@ -312,7 +312,7 @@ public: private: const unsigned numOperands, numResults; - OperationInst(Attribute *location, Identifier name, unsigned numOperands, + OperationInst(Location *location, Identifier name, unsigned numOperands, unsigned numResults, ArrayRef attributes, MLIRContext *context); ~OperationInst(); @@ -358,8 +358,7 @@ public: } protected: - TerminatorInst(Kind kind, Attribute *location) - : Instruction(kind, location) {} + TerminatorInst(Kind kind, Location *location) : Instruction(kind, location) {} ~TerminatorInst() {} }; @@ -367,7 +366,7 @@ protected: /// and may pass basic block arguments to the successor. class BranchInst : public TerminatorInst { public: - static BranchInst *create(Attribute *location, BasicBlock *dest, + static BranchInst *create(Location *location, BasicBlock *dest, ArrayRef operands = {}) { return new BranchInst(location, dest, operands); } @@ -400,9 +399,8 @@ public: } private: - explicit BranchInst(Attribute *location, BasicBlock *dest, + explicit BranchInst(Location *location, BasicBlock *dest, ArrayRef operands); - BasicBlockOperand dest; std::vector operands; }; @@ -415,7 +413,7 @@ class CondBranchInst : public TerminatorInst { enum { trueIndex = 0, falseIndex = 1 }; public: - static CondBranchInst *create(Attribute *location, CFGValue *condition, + static CondBranchInst *create(Location *location, CFGValue *condition, BasicBlock *trueDest, BasicBlock *falseDest) { return new CondBranchInst(location, condition, trueDest, falseDest); } @@ -561,7 +559,7 @@ public: } private: - CondBranchInst(Attribute *location, CFGValue *condition, BasicBlock *trueDest, + CondBranchInst(Location *location, CFGValue *condition, BasicBlock *trueDest, BasicBlock *falseDest); CFGValue *condition; @@ -581,7 +579,7 @@ class ReturnInst final private llvm::TrailingObjects { public: /// Create a new ReturnInst with the specific fields. - static ReturnInst *create(Attribute *location, ArrayRef operands); + static ReturnInst *create(Location *location, ArrayRef operands); unsigned getNumOperands() const { return numOperands; } @@ -606,7 +604,7 @@ private: return numOperands; } - ReturnInst(Attribute *location, unsigned numOperands); + ReturnInst(Location *location, unsigned numOperands); ~ReturnInst(); unsigned numOperands; diff --git a/mlir/include/mlir/IR/Location.h b/mlir/include/mlir/IR/Location.h new file mode 100644 index 000000000000..613d0b6f63c4 --- /dev/null +++ b/mlir/include/mlir/IR/Location.h @@ -0,0 +1,137 @@ +//===- Location.h - MLIR Location Classes -----------------------*- C++ -*-===// +// +// Copyright 2019 The MLIR Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ============================================================================= +// +// These classes provide the ability to relate MLIR objects back to source +// location position information. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_IR_LOCATION_H +#define MLIR_IR_LOCATION_H + +#include "mlir/Support/LLVM.h" +#include "llvm/ADT/StringRef.h" + +namespace mlir { +class MLIRContext; + +/// Location objects represent source locations information in MLIR. +class Location { +public: + enum class Kind { + /// This represents an unknown location. + Unknown, + + /// This represents a file/line/column location. + FileLineCol, + + // Represents a location as a 'void*' pointer to a front-end's opaque + // location information, which must live longer than the MLIR objects that + // refer to it. OpaqueLocation's are never serialized. + // + // TODO: OpaqueLocation, + + // Represents a value inlined through a function call. + // TODO: InlinedLocation, + + // Represents a value composed of multiple source constructs. + // TODO: FusedLocation, + }; + + /// Return the classification for this location. + Kind getKind() const { return kind; } + + /// Print the location. + void print(raw_ostream &os) const; + void dump() const; + +protected: + explicit Location(Kind kind) : kind(kind) {} + ~Location() {} + +private: + /// Classification of the subclass, used for type checking. + Kind kind : 8; + + Location(const Location &) = delete; + void operator=(const Location &) = delete; +}; + +inline raw_ostream &operator<<(raw_ostream &os, const Location &loc) { + loc.print(os); + return os; +} + +/// Represents an unknown location. This is always a singleton for a given +/// MLIRContext. +class UnknownLoc : public Location { +public: + static UnknownLoc *get(MLIRContext *context); + +private: + explicit UnknownLoc() : Location(Kind::Unknown) {} +}; + +/// This class is used to represent a uniqued filename in an MLIRContext. It is +/// a simple wrapper around a const char* to uniqued string memory. +class UniquedFilename { +public: + /// Unique the specified filename and return a stable pointer owned by the + /// specified context. The filename is not allowed to contain embedded ASCII + /// nul (\0) characters. + static UniquedFilename get(StringRef filename, MLIRContext *context); + + StringRef getRef() const { return string; } + const char *data() const { return string; } + +private: + explicit UniquedFilename(const char *string) : string(string) {} + const char *string; +}; + +/// Represents a location derived from a file/line/column location. The column +/// and line may be zero to represent unknown column and/or unknown line/column +/// information. +class FileLineColLoc : public Location { +public: + /// Return a uniqued FileLineCol location object. + static FileLineColLoc *get(UniquedFilename filename, unsigned line, + unsigned column, MLIRContext *context); + + StringRef getFilename() const { return filename.getRef(); } + + unsigned getLine() const { return line; } + unsigned getColumn() const { return column; } + + /// Methods for support type inquiry through isa, cast, and dyn_cast. + static bool classof(const Location *loc) { + return loc->getKind() == Kind::FileLineCol; + } + +private: + FileLineColLoc(UniquedFilename filename, unsigned line, unsigned column) + : Location(Kind::FileLineCol), filename(filename), line(line), + column(column) {} + ~FileLineColLoc() = delete; + + const UniquedFilename filename; + const unsigned line, column; +}; + +} // end namespace mlir + +#endif diff --git a/mlir/include/mlir/IR/MLIRContext.h b/mlir/include/mlir/IR/MLIRContext.h index d782be6ee148..0ea78dd2f5ab 100644 --- a/mlir/include/mlir/IR/MLIRContext.h +++ b/mlir/include/mlir/IR/MLIRContext.h @@ -24,7 +24,7 @@ namespace mlir { class MLIRContextImpl; -class Attribute; +class Location; /// MLIRContext is the top-level object for a collection of MLIR modules. It /// holds immortal uniqued objects like types, and the tables used to unique @@ -58,7 +58,7 @@ public: // notes will be dropped and errors will terminate the process with exit(1). using DiagnosticHandlerTy = std::function; + Location *location, StringRef message, DiagnosticKind kind)>; /// Register a diagnostic handler with this LLVM context. The handler is /// passed location information if present (nullptr if not) along with a @@ -71,7 +71,7 @@ public: /// This emits an diagnostic using the registered issue handle if present, or /// with the default behavior if not. The MLIR compiler should not generally /// interact with this, it should use methods on Operation instead. - void emitDiagnostic(Attribute *location, const Twine &message, + void emitDiagnostic(Location *location, const Twine &message, DiagnosticKind kind) const; private: diff --git a/mlir/include/mlir/IR/Operation.h b/mlir/include/mlir/IR/Operation.h index d5b2b25722b6..f5e3b178059b 100644 --- a/mlir/include/mlir/IR/Operation.h +++ b/mlir/include/mlir/IR/Operation.h @@ -27,6 +27,7 @@ namespace mlir { class Attribute; class AttributeListStorage; class AbstractOperation; +class Location; template class ConstOpPointer; template class OpPointer; template class OperandIterator; @@ -46,7 +47,7 @@ typedef std::pair NamedAttribute; /// this in a collection. struct OperationState { MLIRContext *const context; - Attribute *location; + Location *location; Identifier name; SmallVector operands; /// Types of the results of this operation. @@ -54,14 +55,14 @@ struct OperationState { SmallVector attributes; public: - OperationState(MLIRContext *context, Attribute *location, StringRef name) + OperationState(MLIRContext *context, Location *location, StringRef name) : context(context), location(location), name(Identifier::get(name, context)) {} - OperationState(MLIRContext *context, Attribute *location, Identifier name) + OperationState(MLIRContext *context, Location *location, Identifier name) : context(context), location(location), name(name) {} - OperationState(MLIRContext *context, Attribute *location, StringRef name, + OperationState(MLIRContext *context, Location *location, StringRef name, ArrayRef operands, ArrayRef types, ArrayRef attributes = {}) : context(context), location(location), @@ -92,9 +93,8 @@ public: /// Return the context this operation is associated with. MLIRContext *getContext() const; - /// The source location the operation was defined or derived from. Note that - /// it is possible for this pointer to be null. - Attribute *getLoc() const; + /// The source location the operation was defined or derived from. + Location *getLoc() const; /// Return the function this operation is defined in. This has a verbose /// name to avoid name lookup ambiguities. diff --git a/mlir/include/mlir/IR/Statement.h b/mlir/include/mlir/IR/Statement.h index d6d16e3a775e..55a0aece147b 100644 --- a/mlir/include/mlir/IR/Statement.h +++ b/mlir/include/mlir/IR/Statement.h @@ -29,7 +29,7 @@ #include "llvm/ADT/ilist_node.h" namespace mlir { -class Attribute; +class Location; class MLFunction; class StmtBlock; class ForStmt; @@ -52,9 +52,8 @@ public: /// Return the context this operation is associated with. MLIRContext *getContext() const; - /// The source location the operation was defined or derived from. Note that - /// it is possible for this pointer to be null. - Attribute *getLoc() const { return location; } + /// The source location the operation was defined or derived from. + Location *getLoc() const { return location; } /// Remove this statement from its block and delete it. void eraseFromBlock(); @@ -156,7 +155,10 @@ public: void emitNote(const Twine &message) const; protected: - Statement(Kind kind, Attribute *location) : kind(kind), location(location) {} + Statement(Kind kind, Location *location) : kind(kind), location(location) { + assert(location && "location should never be null"); + } + // Statements are deleted through the destroy() member because this class // does not have a virtual destructor. ~Statement(); @@ -168,7 +170,7 @@ private: /// This holds information about the source location the operation was defined /// or derived from. - Attribute *location; + Location *location; // allow ilist_traits access to 'block' field. friend struct llvm::ilist_traits; diff --git a/mlir/include/mlir/IR/Statements.h b/mlir/include/mlir/IR/Statements.h index 1aa6581a3468..c5af5d5ce29a 100644 --- a/mlir/include/mlir/IR/Statements.h +++ b/mlir/include/mlir/IR/Statements.h @@ -40,7 +40,7 @@ class OperationStmt final private llvm::TrailingObjects { public: /// Create a new OperationStmt with the specific fields. - static OperationStmt *create(Attribute *location, Identifier name, + static OperationStmt *create(Location *location, Identifier name, ArrayRef operands, ArrayRef resultTypes, ArrayRef attributes, @@ -180,7 +180,7 @@ public: private: const unsigned numOperands, numResults; - OperationStmt(Attribute *location, Identifier name, unsigned numOperands, + OperationStmt(Location *location, Identifier name, unsigned numOperands, unsigned numResults, ArrayRef attributes, MLIRContext *context); ~OperationStmt(); @@ -198,7 +198,7 @@ private: /// For statement represents an affine loop nest. class ForStmt : public Statement, public MLValue, public StmtBlock { public: - static ForStmt *create(Attribute *location, ArrayRef lbOperands, + static ForStmt *create(Location *location, ArrayRef lbOperands, AffineMap *lbMap, ArrayRef ubOperands, AffineMap *ubMap, int64_t step, MLIRContext *context); @@ -336,7 +336,7 @@ private: // Operands for the lower and upper bounds. std::vector operands; - explicit ForStmt(Attribute *location, unsigned numOperands, AffineMap *lbMap, + explicit ForStmt(Location *location, unsigned numOperands, AffineMap *lbMap, AffineMap *ubMap, int64_t step, MLIRContext *context); }; @@ -412,7 +412,7 @@ private: /// If statement restricts execution to a subset of the loop iteration space. class IfStmt : public Statement { public: - explicit IfStmt(Attribute *location, IntegerSet *condition); + explicit IfStmt(Location *location, IntegerSet *condition); ~IfStmt(); IfClause *getThen() const { return thenClause; } diff --git a/mlir/lib/IR/Builders.cpp b/mlir/lib/IR/Builders.cpp index 376d54e9a45b..8d0f2234ad36 100644 --- a/mlir/lib/IR/Builders.cpp +++ b/mlir/lib/IR/Builders.cpp @@ -20,6 +20,7 @@ #include "mlir/IR/AffineMap.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/IntegerSet.h" +#include "mlir/IR/Location.h" #include "mlir/IR/Module.h" #include "mlir/IR/Types.h" using namespace mlir; @@ -32,6 +33,21 @@ Identifier Builder::getIdentifier(StringRef str) { Module *Builder::createModule() { return new Module(context); } +//===----------------------------------------------------------------------===// +// Locations. +//===----------------------------------------------------------------------===// + +UnknownLoc *Builder::getUnknownLoc() { return UnknownLoc::get(context); } + +UniquedFilename Builder::getUniquedFilename(StringRef filename) { + return UniquedFilename::get(filename, context); +} + +FileLineColLoc *Builder::getFileLineColLoc(UniquedFilename filename, + unsigned line, unsigned column) { + return FileLineColLoc::get(filename, line, column, context); +} + //===----------------------------------------------------------------------===// // Types. //===----------------------------------------------------------------------===// @@ -227,7 +243,7 @@ OperationStmt *MLFuncBuilder::createOperation(const OperationState &state) { return op; } -ForStmt *MLFuncBuilder::createFor(Attribute *location, +ForStmt *MLFuncBuilder::createFor(Location *location, ArrayRef lbOperands, AffineMap *lbMap, ArrayRef ubOperands, @@ -238,7 +254,7 @@ ForStmt *MLFuncBuilder::createFor(Attribute *location, return stmt; } -IfStmt *MLFuncBuilder::createIf(Attribute *location, IntegerSet *condition) { +IfStmt *MLFuncBuilder::createIf(Location *location, IntegerSet *condition) { auto *stmt = new IfStmt(location, condition); block->getStatements().insert(insertPoint, stmt); return stmt; diff --git a/mlir/lib/IR/Instructions.cpp b/mlir/lib/IR/Instructions.cpp index bd487833074a..90a50160054f 100644 --- a/mlir/lib/IR/Instructions.cpp +++ b/mlir/lib/IR/Instructions.cpp @@ -146,8 +146,8 @@ void Instruction::emitError(const Twine &message) const { // OperationInst //===----------------------------------------------------------------------===// -/// Create a new OperationInst with the specific fields. -OperationInst *OperationInst::create(Attribute *location, Identifier name, +/// Create a new OperationInst with the specified fields. +OperationInst *OperationInst::create(Location *location, Identifier name, ArrayRef operands, ArrayRef resultTypes, ArrayRef attributes, @@ -186,7 +186,7 @@ OperationInst *OperationInst::clone() const { getContext()); } -OperationInst::OperationInst(Attribute *location, Identifier name, +OperationInst::OperationInst(Location *location, Identifier name, unsigned numOperands, unsigned numResults, ArrayRef attributes, MLIRContext *context) @@ -281,7 +281,7 @@ MutableArrayRef TerminatorInst::getBasicBlockOperands() { //===----------------------------------------------------------------------===// /// Create a new OperationInst with the specific fields. -ReturnInst *ReturnInst::create(Attribute *location, +ReturnInst *ReturnInst::create(Location *location, ArrayRef operands) { auto byteSize = totalSizeToAlloc(operands.size()); void *rawMem = malloc(byteSize); @@ -296,7 +296,7 @@ ReturnInst *ReturnInst::create(Attribute *location, return inst; } -ReturnInst::ReturnInst(Attribute *location, unsigned numOperands) +ReturnInst::ReturnInst(Location *location, unsigned numOperands) : TerminatorInst(Kind::Return, location), numOperands(numOperands) {} void ReturnInst::destroy() { @@ -314,7 +314,7 @@ ReturnInst::~ReturnInst() { // BranchInst //===----------------------------------------------------------------------===// -BranchInst::BranchInst(Attribute *location, BasicBlock *dest, +BranchInst::BranchInst(Location *location, BasicBlock *dest, ArrayRef operands) : TerminatorInst(Kind::Branch, location), dest(this, dest) { addOperands(operands); @@ -338,7 +338,7 @@ void BranchInst::addOperands(ArrayRef values) { // CondBranchInst //===----------------------------------------------------------------------===// -CondBranchInst::CondBranchInst(Attribute *location, CFGValue *condition, +CondBranchInst::CondBranchInst(Location *location, CFGValue *condition, BasicBlock *trueDest, BasicBlock *falseDest) : TerminatorInst(Kind::CondBranch, location), condition(condition), dests{{this}, {this}}, numTrueOperands(0) { diff --git a/mlir/lib/IR/MLIRContext.cpp b/mlir/lib/IR/MLIRContext.cpp index 024e1b6395e0..46d010349d66 100644 --- a/mlir/lib/IR/MLIRContext.cpp +++ b/mlir/lib/IR/MLIRContext.cpp @@ -23,6 +23,7 @@ #include "mlir/IR/Function.h" #include "mlir/IR/Identifier.h" #include "mlir/IR/IntegerSet.h" +#include "mlir/IR/Location.h" #include "mlir/IR/OperationSet.h" #include "mlir/IR/StandardOps.h" #include "mlir/IR/Types.h" @@ -182,12 +183,26 @@ namespace mlir { /// This class is completely private to this file, so everything is public. class MLIRContextImpl { public: - /// We put immortal objects into this allocator. - llvm::BumpPtrAllocator allocator; - /// This is the set of all operations that are registered with the system. OperationSet operationSet; + /// We put location info into this allocator, since it is generally not + /// touched by compiler passes. + llvm::BumpPtrAllocator locationAllocator; + + /// The singleton for UnknownLoc. + UnknownLoc *theUnknownLoc = nullptr; + + /// These are filename locations uniqued into this MLIRContext. + llvm::StringMap filenames; + + /// FileLineColLoc uniquing. + DenseMap, FileLineColLoc *> + fileLineColLocs; + + /// We put immortal objects into this allocator. + llvm::BumpPtrAllocator allocator; + /// This is the handler to use to report diagnostics, or null if not /// registered. MLIRContext::DiagnosticHandlerTy diagnosticHandler; @@ -258,7 +273,7 @@ public: DenseMap functionAttrs; public: - MLIRContextImpl() : identifiers(allocator) { + MLIRContextImpl() : filenames(locationAllocator), identifiers(allocator) { registerStandardOperations(operationSet); } @@ -293,8 +308,7 @@ auto MLIRContext::getDiagnosticHandler() const -> DiagnosticHandlerTy { /// This emits a diagnostic using the registered issue handle if present, or /// with the default behavior if not. The MLIR compiler should not generally /// interact with this, it should use methods on Operation instead. -void MLIRContext::emitDiagnostic(Attribute *location, - const llvm::Twine &message, +void MLIRContext::emitDiagnostic(Location *location, const llvm::Twine &message, DiagnosticKind kind) const { // If we had a handler registered, emit the diagnostic using it. auto handler = getImpl().diagnosticHandler; @@ -305,6 +319,8 @@ void MLIRContext::emitDiagnostic(Attribute *location, if (kind != DiagnosticKind::Error) return; + // TODO(clattner): can improve this now! + // The default behavior for errors is to emit them to stderr and exit. llvm::errs() << message.str() << "\n"; llvm::errs().flush(); @@ -337,6 +353,39 @@ Identifier Identifier::get(StringRef str, const MLIRContext *context) { return Identifier(it->getKeyData()); } +//===----------------------------------------------------------------------===// +// Location uniquing +//===----------------------------------------------------------------------===// + +UnknownLoc *UnknownLoc::get(MLIRContext *context) { + auto &impl = context->getImpl(); + if (auto *result = impl.theUnknownLoc) + return result; + + impl.theUnknownLoc = impl.allocator.Allocate(); + new (impl.theUnknownLoc) UnknownLoc(); + return impl.theUnknownLoc; +} + +UniquedFilename UniquedFilename::get(StringRef filename, MLIRContext *context) { + auto &impl = context->getImpl(); + auto it = impl.filenames.insert({filename, char()}).first; + return UniquedFilename(it->getKeyData()); +} + +FileLineColLoc *FileLineColLoc::get(UniquedFilename filename, unsigned line, + unsigned column, MLIRContext *context) { + auto &impl = context->getImpl(); + auto &entry = + impl.fileLineColLocs[std::make_tuple(filename.data(), line, column)]; + if (!entry) { + entry = impl.allocator.Allocate(); + new (entry) FileLineColLoc(filename, line, column); + } + + return entry; +} + //===----------------------------------------------------------------------===// // Type uniquing //===----------------------------------------------------------------------===// diff --git a/mlir/lib/IR/Operation.cpp b/mlir/lib/IR/Operation.cpp index 71167bde38de..f5d07d558108 100644 --- a/mlir/lib/IR/Operation.cpp +++ b/mlir/lib/IR/Operation.cpp @@ -46,7 +46,7 @@ MLIRContext *Operation::getContext() const { /// The source location the operation was defined or derived from. Note that /// it is possible for this pointer to be null. -Attribute *Operation::getLoc() const { +Location *Operation::getLoc() const { if (auto *inst = dyn_cast(this)) return inst->getLoc(); return cast(this)->getLoc(); diff --git a/mlir/lib/IR/Statement.cpp b/mlir/lib/IR/Statement.cpp index 3746f718689e..3f95a946528f 100644 --- a/mlir/lib/IR/Statement.cpp +++ b/mlir/lib/IR/Statement.cpp @@ -209,7 +209,7 @@ void Statement::eraseFromBlock() { //===----------------------------------------------------------------------===// /// Create a new OperationStmt with the specific fields. -OperationStmt *OperationStmt::create(Attribute *location, Identifier name, +OperationStmt *OperationStmt::create(Location *location, Identifier name, ArrayRef operands, ArrayRef resultTypes, ArrayRef attributes, @@ -233,7 +233,7 @@ OperationStmt *OperationStmt::create(Attribute *location, Identifier name, return stmt; } -OperationStmt::OperationStmt(Attribute *location, Identifier name, +OperationStmt::OperationStmt(Location *location, Identifier name, unsigned numOperands, unsigned numResults, ArrayRef attributes, MLIRContext *context) @@ -275,7 +275,7 @@ bool OperationStmt::isReturn() const { return is(); } // ForStmt //===----------------------------------------------------------------------===// -ForStmt *ForStmt::create(Attribute *location, ArrayRef lbOperands, +ForStmt *ForStmt::create(Location *location, ArrayRef lbOperands, AffineMap *lbMap, ArrayRef ubOperands, AffineMap *ubMap, int64_t step, MLIRContext *context) { assert(lbOperands.size() == lbMap->getNumOperands() && @@ -297,7 +297,7 @@ ForStmt *ForStmt::create(Attribute *location, ArrayRef lbOperands, return stmt; } -ForStmt::ForStmt(Attribute *location, unsigned numOperands, AffineMap *lbMap, +ForStmt::ForStmt(Location *location, unsigned numOperands, AffineMap *lbMap, AffineMap *ubMap, int64_t step, MLIRContext *context) : Statement(Kind::For, location), MLValue(MLValueKind::ForStmt, Type::getAffineInt(context)), @@ -357,7 +357,7 @@ void ForStmt::setConstantUpperBound(int64_t value) { // IfStmt //===----------------------------------------------------------------------===// -IfStmt::IfStmt(Attribute *location, IntegerSet *condition) +IfStmt::IfStmt(Location *location, IntegerSet *condition) : Statement(Kind::If, location), thenClause(new IfClause(this)), elseClause(nullptr), condition(condition) {} diff --git a/mlir/lib/Parser/Parser.cpp b/mlir/lib/Parser/Parser.cpp index 756f25d8bbd4..ebeb19616a44 100644 --- a/mlir/lib/Parser/Parser.cpp +++ b/mlir/lib/Parser/Parser.cpp @@ -25,6 +25,7 @@ #include "mlir/IR/AffineMap.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/Builders.h" +#include "mlir/IR/Location.h" #include "mlir/IR/MLFunction.h" #include "mlir/IR/MLIRContext.h" #include "mlir/IR/Module.h" @@ -43,6 +44,14 @@ using llvm::SourceMgr; /// bool value. Failure is "true" in a boolean context. enum ParseResult { ParseSuccess, ParseFailure }; +/// Return a uniqued filename for the main file the specified SourceMgr is +/// looking at. +static UniquedFilename getUniquedFilename(llvm::SourceMgr &sourceMgr, + MLIRContext *context) { + auto *buffer = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID()); + return UniquedFilename::get(buffer->getBufferIdentifier(), context); +} + namespace { class Parser; @@ -54,6 +63,7 @@ public: ParserState(llvm::SourceMgr &sourceMgr, Module *module, SMDiagnosticHandlerTy errorReporter) : context(module->getContext()), module(module), + filename(getUniquedFilename(sourceMgr, context)), lex(sourceMgr, errorReporter), curToken(lex.lexToken()), errorReporter(errorReporter), operationSet(OperationSet::get(context)) { } @@ -81,6 +91,9 @@ private: // This is the module we are parsing into. Module *const module; + /// The filename to use for location generation. + UniquedFilename filename; + // The lexer for the source file we're parsing. Lexer lex; @@ -122,7 +135,7 @@ public: /// Encode the specified source location information into an attribute for /// attachment to the IR. - Attribute *getEncodedSourceLocation(llvm::SMLoc loc); + Location *getEncodedSourceLocation(llvm::SMLoc loc); /// Emit an error and return failure. ParseResult emitError(const Twine &message) { @@ -209,16 +222,13 @@ private: /// Encode the specified source location information into an attribute for /// attachment to the IR. -Attribute *Parser::getEncodedSourceLocation(llvm::SMLoc loc) { - // TODO(clattner): Switch to an more structured form that includes - // file/line/column instead of just byte offset in the file. This will - // eliminate this block of low level code poking at the SourceMgr directly. +Location *Parser::getEncodedSourceLocation(llvm::SMLoc loc) { auto &sourceMgr = getSourceMgr(); - auto fileID = sourceMgr.FindBufferContainingLoc(loc); + auto lineAndColumn = + sourceMgr.getLineAndColumn(loc, sourceMgr.getMainFileID()); - auto *srcBuffer = sourceMgr.getMemoryBuffer(fileID); - unsigned locationEncoding = loc.getPointer() - srcBuffer->getBufferStart(); - return builder.getIntegerAttr(locationEncoding); + return FileLineColLoc::get(state.filename, lineAndColumn.first, + lineAndColumn.second, getContext()); } ParseResult Parser::emitError(SMLoc loc, const Twine &message) { @@ -1389,11 +1399,9 @@ SSAValue *FunctionParser::createForwardReferencePlaceholder(SMLoc loc, // We create these placeholders as having an empty name, which we know cannot // be created through normal user input, allowing us to distinguish them. auto name = Identifier::get("placeholder", getContext()); - auto *inst = - // FIXME(clattner): encode the location into the placeholder instead of - // into the forwardReferencePlaceholders map! - OperationInst::create(/*location=*/nullptr, name, /*operands=*/{}, type, - /*attrs=*/{}, getContext()); + auto *inst = OperationInst::create(getEncodedSourceLocation(loc), name, + /*operands=*/{}, type, + /*attributes=*/{}, getContext()); forwardReferencePlaceholders[inst->getResult(0)] = loc; return inst->getResult(0); } @@ -3038,11 +3046,8 @@ Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context, auto existingContextHandler = context->getDiagnosticHandler(); // Install a new handler that uses the error reporter. - context->registerDiagnosticHandler([&](Attribute *location, StringRef message, + context->registerDiagnosticHandler([&](Location *location, StringRef message, MLIRContext::DiagnosticKind kind) { - auto offset = cast(location)->getValue(); - auto *mainBuffer = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID()); - auto ptr = mainBuffer->getBufferStart() + offset; SourceMgr::DiagKind diagKind; switch (kind) { case MLIRContext::DiagnosticKind::Error: @@ -3055,8 +3060,20 @@ Module *mlir::parseSourceFile(llvm::SourceMgr &sourceMgr, MLIRContext *context, diagKind = SourceMgr::DK_Note; break; } - errorReporter( - sourceMgr.GetMessage(SMLoc::getFromPointer(ptr), diagKind, message)); + + StringRef filename; + unsigned line = 0, column = 0; + if (auto fileLoc = dyn_cast(location)) { + filename = fileLoc->getFilename(); + line = fileLoc->getLine(); + column = fileLoc->getColumn(); + } + + auto diag = llvm::SMDiagnostic(sourceMgr, SMLoc(), filename, line, column, + diagKind, message, /*LineStr=*/StringRef(), + /*Ranges=*/{}, /*FixIts=*/{}); + + errorReporter(diag); }); // This is the result module we are parsing into.