• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include <memory>
17 #include <utility>
18 
19 #include "llvm/IR/Module.h"
20 #include "tensorflow/compiler/xla/literal.h"
21 #include "tensorflow/compiler/xla/service/buffer_assignment.h"
22 #include "tensorflow/compiler/xla/service/cpu/tests/cpu_codegen_test.h"
23 #include "tensorflow/compiler/xla/service/hlo_computation.h"
24 #include "tensorflow/compiler/xla/service/hlo_instruction.h"
25 #include "tensorflow/compiler/xla/service/hlo_module.h"
26 #include "tensorflow/compiler/xla/service/llvm_ir/alias_analysis.h"
27 #include "tensorflow/compiler/xla/service/llvm_ir/llvm_util.h"
28 #include "tensorflow/compiler/xla/shape_util.h"
29 #include "tensorflow/compiler/xla/tests/filecheck.h"
30 #include "tensorflow/compiler/xla/xla_data.pb.h"
31 #include "tensorflow/core/platform/test.h"
32 
33 namespace xla {
34 namespace cpu {
35 
36 class CpuNoAliasTest : public CpuCodegenTest {};
37 
38 // Creates a simple HLO ir_module (runs concat(concat(x, y), x)), and then
39 // inspects the aliasing information for loads to its buffers.
TEST_F(CpuNoAliasTest,Concat)40 TEST_F(CpuNoAliasTest, Concat) {
41   HloComputation::Builder builder(TestName());
42 
43   Literal literal = LiteralUtil::CreateR2<float>({{1.0, 2.0}, {3.0, 4.0}});
44   auto param_shape = ShapeUtil::MakeShape(F32, {2, 2});
45   HloInstruction* param_x = builder.AddInstruction(
46       HloInstruction::CreateParameter(0, param_shape, "x"));
47   HloInstruction* param_y = builder.AddInstruction(
48       HloInstruction::CreateParameter(1, param_shape, "y"));
49   HloInstruction* concat1 =
50       builder.AddInstruction(HloInstruction::CreateConcatenate(
51           ShapeUtil::MakeShape(F32, {2, 4}), {param_x, param_y}, 1));
52   HloInstruction* concat2 =
53       builder.AddInstruction(HloInstruction::CreateConcatenate(
54           ShapeUtil::MakeShape(F32, {2, 6}), {concat1, param_x}, 1));
55   HloInstruction* add = builder.AddInstruction(HloInstruction::CreateBinary(
56       ShapeUtil::MakeShape(F32, {2, 6}), HloOpcode::kAdd, concat2, concat2));
57 
58   std::unique_ptr<HloComputation> computation = builder.Build();
59 
60   auto hlo_module = CreateNewVerifiedModule();
61   hlo_module->AddEntryComputation(std::move(computation));
62 
63   // Now that we have an HLO module, build an llvm_ir::AliasAnalysis for it.
64   auto status_or_buffer_assn = BufferAssigner::Run(
65       hlo_module.get(),
66       std::make_unique<DependencyHloOrdering>(hlo_module.get()),
67       backend().compiler()->BufferSizeBytesFunction(),
68       [](LogicalBuffer::Color) { return /*alignment=*/1; });
69   ASSERT_EQ(status_or_buffer_assn.status(), OkStatus());
70 
71   llvm::LLVMContext context;
72   llvm_ir::AliasAnalysis aa(*hlo_module, *status_or_buffer_assn.ValueOrDie(),
73                             &context);
74 
75   // Construct an LLVM module containing loads that we annotate as being from
76   // the buffers in the HLO module.  We'll inspect these loads to ensure that
77   // they have the expected alias information.
78   llvm::Module ir_module("test", context);
79   llvm::Function* func = llvm::dyn_cast<llvm::Function>(
80       ir_module.getOrInsertFunction("test_fn", llvm::Type::getVoidTy(context))
81           .getCallee());
82   llvm::BasicBlock* bb = llvm::BasicBlock::Create(context, "body", func);
83   llvm::IRBuilder<> b(bb);
84   auto* zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0);
85 
86   llvm::ArrayType* array2d_type = llvm::ArrayType::get(
87       llvm::ArrayType::get(llvm::Type::getFloatTy(context), 100), 100);
88 
89   {
90     auto param_x_val = llvm::cast<llvm::GlobalVariable>(
91         ir_module.getOrInsertGlobal("param_x", array2d_type));
92     llvm_ir::IrArray param_x_array(param_x_val, param_x_val->getValueType(),
93                                    param_shape);
94     aa.AddAliasingInformationToIrArray(*param_x, &param_x_array);
95     llvm_ir::IrArray::Index zero_2d({zero, zero}, param_shape, zero->getType());
96     param_x_array.EmitReadArrayElement(zero_2d, &b)
97         ->setName("read_param_x_array");
98   }
99 
100   {
101     auto concat1_val = llvm::cast<llvm::GlobalVariable>(
102         ir_module.getOrInsertGlobal("concat1", array2d_type));
103     auto shape = ShapeUtil::MakeShape(F32, {2, 4});
104     llvm_ir::IrArray concat1_array(concat1_val, concat1_val->getValueType(),
105                                    shape);
106     aa.AddAliasingInformationToIrArray(*concat1, &concat1_array);
107     llvm_ir::IrArray::Index zero_2d({zero, zero}, shape, zero->getType());
108     concat1_array.EmitReadArrayElement(zero_2d, &b)
109         ->setName("read_concat1_array");
110   }
111 
112   {
113     auto concat2_val = llvm::cast<llvm::GlobalVariable>(
114         ir_module.getOrInsertGlobal("concat2", array2d_type));
115     auto shape = ShapeUtil::MakeShape(F32, {2, 6});
116     llvm_ir::IrArray concat2_array(concat2_val, concat2_val->getValueType(),
117                                    shape);
118     aa.AddAliasingInformationToIrArray(*concat2, &concat2_array);
119     llvm_ir::IrArray::Index zero_2d({zero, zero}, shape, zero->getType());
120     concat2_array.EmitReadArrayElement(zero_2d, &b)
121         ->setName("read_concat2_array");
122   }
123 
124   {
125     auto concat2_val = llvm::cast<llvm::GlobalVariable>(
126         ir_module.getOrInsertGlobal("add", array2d_type));
127     auto shape = ShapeUtil::MakeShape(F32, {2, 6});
128     llvm_ir::IrArray add_array(concat2_val, concat2_val->getValueType(), shape);
129     aa.AddAliasingInformationToIrArray(*add, &add_array);
130     llvm_ir::IrArray::Index zero_2d({zero, zero}, shape, zero->getType());
131     add_array.EmitReadArrayElement(zero_2d, &b)->setName("read_add_array");
132   }
133 
134   // Check the AA info in the loads.
135   const char* filecheck_pattern = R"(
136     CHECK: %read_param_x_array = load {{.*}} !noalias [[param_x_noalias:![0-9]+]]
137     CHECK: %read_concat1_array = load {{.*}} !alias.scope [[concat1_scope:![0-9]+]], !noalias [[concat1_noalias:![0-9]+]]
138     CHECK: %read_concat2_array = load {{.*}} !alias.scope [[concat1_noalias]], !noalias [[concat1_scope]]
139     CHECK: %read_add_array = load {{.*}} !alias.scope [[concat1_noalias]]{{$}}
140     CHECK-DAG: [[buf_size32:![0-9]+]] = !{!"buffer:{{.*}} size:32
141     CHECK-DAG: [[buf_size48:![0-9]+]] = !{!"buffer:{{.*}} size:48
142     CHECK-DAG: [[param_x_noalias]] = !{[[buf_size48]], [[buf_size32]]}
143     CHECK-DAG: [[concat1_scope]] = !{[[buf_size32]]}
144     CHECK-DAG: [[concat1_noalias]] = !{[[buf_size48]]}
145   )";
146 
147   TF_ASSERT_OK_AND_ASSIGN(
148       bool filecheck_match,
149       RunFileCheck(llvm_ir::DumpModuleToString(ir_module), filecheck_pattern));
150   EXPECT_TRUE(filecheck_match);
151 }
152 
153 }  // namespace cpu
154 }  // namespace xla
155