aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/compiler/xla/service/llvm_ir/llvm_loop.h
diff options
context:
space:
mode:
Diffstat (limited to 'tensorflow/compiler/xla/service/llvm_ir/llvm_loop.h')
-rw-r--r--tensorflow/compiler/xla/service/llvm_ir/llvm_loop.h230
1 files changed, 230 insertions, 0 deletions
diff --git a/tensorflow/compiler/xla/service/llvm_ir/llvm_loop.h b/tensorflow/compiler/xla/service/llvm_ir/llvm_loop.h
new file mode 100644
index 0000000000..0cc82b040d
--- /dev/null
+++ b/tensorflow/compiler/xla/service/llvm_ir/llvm_loop.h
@@ -0,0 +1,230 @@
+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+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.
+==============================================================================*/
+
+#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_LLVM_IR_LLVM_LOOP_H_
+#define TENSORFLOW_COMPILER_XLA_SERVICE_LLVM_IR_LLVM_LOOP_H_
+
+#include <memory>
+#include <string>
+
+#include "external/llvm/include/llvm/IR/BasicBlock.h"
+#include "external/llvm/include/llvm/IR/IRBuilder.h"
+#include "external/llvm/include/llvm/IR/Value.h"
+#include "tensorflow/compiler/xla/service/llvm_ir/ir_array.h"
+#include "tensorflow/compiler/xla/types.h"
+#include "tensorflow/compiler/xla/xla_data.pb.h"
+#include "tensorflow/core/lib/core/stringpiece.h"
+#include "tensorflow/core/lib/gtl/array_slice.h"
+#include "tensorflow/core/platform/macros.h"
+#include "tensorflow/core/platform/types.h"
+
+namespace xla {
+namespace llvm_ir {
+
+// A class for constructing a for-loop in LLVM IR.
+class ForLoop {
+ public:
+ // Emit a for-loop at the current insert point of the given IRBuilder.
+ //
+ // start_index and end_index are the loop bounds (end_index is not inclusive).
+ // `step` is the increment of the loop index after each iteration.
+ //
+ // The current insert basic block of the builder is the preheader to the loop
+ // (see below for definition of basic block names). All instructions (if any)
+ // at or after the insert point in the insert basic block are moved to a newly
+ // created exit basic block. Instructions before the insert point remain in
+ // the insert BB:
+ //
+ // /--------------\ /----------------\
+ // | insert BB | | insert BB |
+ // | ... | | (preheader BB) |
+ // | %foo = ... | | ... |
+ // insert point ->| %bar = ... | ===> | %foo = ... |
+ // | ... | \----------------/
+ // \--------------/ |
+ // V
+ // [[ LOOP BBs ]]
+ // |
+ // V
+ // /--------------\
+ // | exit BB |
+ // | %bar = ... |
+ // | ... |
+ // \--------------/
+ //
+ // `suffix` is a string used to disambiguate variable and basic block names
+ // emitted in LLVM IR. This string is appended to the name of the induction
+ // variable value and each basic block created for the loop. The builder
+ // insert point is set to the end of the exit block after the function
+ // returns.
+ static std::unique_ptr<ForLoop> EmitForLoop(tensorflow::StringPiece suffix,
+ llvm::Value* start_index,
+ llvm::Value* end_index,
+ llvm::Value* step,
+ llvm::IRBuilder<>* ir_builder);
+
+ // The names of the blocks follow LLVM's conventions. Control flow amongst the
+ // blocks for the example C code looks like:
+ //
+ // for (int i = 0; i < n; ++i) {
+ // do_stuff(i);
+ // }
+ //
+ // /--------------\
+ // | preheader BB |
+ // | i = 0 |
+ // \--------------/
+ // |
+ // V
+ // /-------------\
+ // | header BB |<-+
+ // | if i < n: | |
+ // | goto body | |
+ // | else: | |
+ // | goto exit | |
+ // \-------------/ |
+ // | | |
+ // +--------+ | |
+ // | V |
+ // | /-------------\ |
+ // | | body BB | |
+ // | | dostuff(i) |--+
+ // | | ++i |
+ // | \-------------/
+ // |
+ // | /-------------\
+ // +->| exit BB |
+ // \-------------/
+ //
+ // Caller-emitted code to execute within the loop should be placed within the
+ // "body" basic block.
+ //
+ // Return pointers to various blocks in the loop.
+ llvm::BasicBlock* GetPreheaderBasicBlock() const { return preheader_bb_; }
+ llvm::BasicBlock* GetHeaderBasicBlock() const { return header_bb_; }
+ llvm::BasicBlock* GetBodyBasicBlock() const { return body_bb_; }
+ llvm::BasicBlock* GetExitBasicBlock() const { return exit_bb_; }
+
+ // Return the Value representing the induction variable in the body basic
+ // block of the loop.
+ llvm::Value* GetIndVarValue() const { return indvar_; }
+
+ private:
+ ForLoop(tensorflow::StringPiece suffix, llvm::Value* start_index,
+ llvm::Value* end_index, llvm::Value* step);
+
+ // Emit the loop at the insert point of the builder.
+ void Emit(llvm::IRBuilder<>* ir_builder);
+
+ llvm::BasicBlock* CreateBasicBlockWithSuffix(tensorflow::StringPiece name,
+ llvm::IRBuilder<>* ir_builder);
+
+ // Create a name for an LLVM construct appending the member suffix_ if it is
+ // set.
+ string GetNameWithSuffix(tensorflow::StringPiece name);
+
+ string suffix_;
+ llvm::Value* start_index_;
+ llvm::Value* end_index_;
+ llvm::Value* step_;
+
+ // To improve readability of the IR, we want the basic blocks to appear
+ // consecutively in the following order: preheader, header, body, loop,
+ // exit. The member insert_before_bb_ points to where the next basic block
+ // should be created to ensure this ordering.
+ llvm::BasicBlock* insert_before_bb_;
+
+ llvm::BasicBlock* preheader_bb_;
+ llvm::BasicBlock* header_bb_;
+ llvm::BasicBlock* body_bb_;
+ llvm::BasicBlock* exit_bb_;
+ llvm::Value* indvar_;
+
+ TF_DISALLOW_COPY_AND_ASSIGN(ForLoop);
+};
+
+// A simple class for constructing nested for-loops.
+class ForLoopNest {
+ public:
+ explicit ForLoopNest(llvm::IRBuilder<>* ir_builder)
+ : outer_loop_preheader_bb_(nullptr),
+ outer_loop_exit_bb_(nullptr),
+ inner_loop_body_bb_(nullptr),
+ ir_builder_(ir_builder) {}
+
+ // Adds a loop to the nest. If no loop has been added yet then emit a loop at
+ // the current insert point of the given builder. If one or more loops have
+ // been added then emit loop inside the body of the last added loop.
+ std::unique_ptr<ForLoop> AddLoop(tensorflow::StringPiece suffix,
+ llvm::Value* start_index,
+ llvm::Value* end_index);
+
+ // A convenient wrapper of the other flavor of AddLoop. The given start and
+ // end index are constant.
+ std::unique_ptr<ForLoop> AddLoop(int64 start_index, int64 end_index,
+ tensorflow::StringPiece suffix);
+
+ // Add loops to iterate through the indices within the specified
+ // shape. The returned index collects the induction variables of the
+ // loops so that it will iterate through all coordinates within the
+ // specified shape.
+ //
+ // E.g. if you pass in a 2x3 shape, you will get back an index with
+ // two entries that are induction variables of the two loops that
+ // will be added. That index will iterate through the 6 coordinates
+ // within the shape. One possible order for that sequence would be:
+ //
+ // (0,0), (0,1), (0,2), (1,0), (1,1), (1,2)
+ IrArray::Index AddLoopsForShape(const Shape& shape,
+ tensorflow::StringPiece suffix);
+
+ // Add a loop for each dimension in "dimensions". "suffix" is the
+ // name suffix of the indvar and basic blocks in this new loop nest.
+ //
+ // The return value is an index with the induction variables. The
+ // size equals the rank of shape and there is a null for each
+ // dimension that is not in "dimensions".
+ IrArray::Index AddLoopsForShapeOnDimensions(
+ const Shape& shape, tensorflow::gtl::ArraySlice<int64> dimensions,
+ tensorflow::StringPiece suffix);
+
+ // Convenience methods which return particular basic blocks of the outermost
+ // or innermost loops. These methods return nullptr if no loops have been
+ // added yet.
+ llvm::BasicBlock* GetOuterLoopPreheaderBasicBlock() {
+ return outer_loop_preheader_bb_;
+ }
+ llvm::BasicBlock* GetOuterLoopExitBasicBlock() { return outer_loop_exit_bb_; }
+ llvm::BasicBlock* GetInnerLoopBodyBasicBlock() { return inner_loop_body_bb_; }
+
+ private:
+ // The preheader and exit basic block of the outermost loop, or nullptr if no
+ // loop has been added yet.
+ llvm::BasicBlock* outer_loop_preheader_bb_;
+ llvm::BasicBlock* outer_loop_exit_bb_;
+
+ // The body basic block of the most-recently added loop, or nullptr if no loop
+ // has been added yet.
+ llvm::BasicBlock* inner_loop_body_bb_;
+
+ llvm::IRBuilder<>* ir_builder_;
+
+ TF_DISALLOW_COPY_AND_ASSIGN(ForLoopNest);
+};
+
+} // namespace llvm_ir
+} // namespace xla
+
+#endif // TENSORFLOW_COMPILER_XLA_SERVICE_LLVM_IR_LLVM_LOOP_H_