1fd4e5da5Sopenharmony_ci// Copyright (c) 2018 Google Inc.
2fd4e5da5Sopenharmony_ci//
3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License.
5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at
6fd4e5da5Sopenharmony_ci//
7fd4e5da5Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8fd4e5da5Sopenharmony_ci//
9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and
13fd4e5da5Sopenharmony_ci// limitations under the License.
14fd4e5da5Sopenharmony_ci
15fd4e5da5Sopenharmony_ci#include "source/opt/ir_builder.h"
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include <memory>
18fd4e5da5Sopenharmony_ci#include <vector>
19fd4e5da5Sopenharmony_ci
20fd4e5da5Sopenharmony_ci#include "effcee/effcee.h"
21fd4e5da5Sopenharmony_ci#include "gtest/gtest.h"
22fd4e5da5Sopenharmony_ci#include "source/opt/basic_block.h"
23fd4e5da5Sopenharmony_ci#include "source/opt/build_module.h"
24fd4e5da5Sopenharmony_ci#include "source/opt/instruction.h"
25fd4e5da5Sopenharmony_ci#include "source/opt/type_manager.h"
26fd4e5da5Sopenharmony_ci#include "spirv-tools/libspirv.hpp"
27fd4e5da5Sopenharmony_ci
28fd4e5da5Sopenharmony_cinamespace spvtools {
29fd4e5da5Sopenharmony_cinamespace opt {
30fd4e5da5Sopenharmony_cinamespace {
31fd4e5da5Sopenharmony_ci
32fd4e5da5Sopenharmony_ciusing Analysis = IRContext::Analysis;
33fd4e5da5Sopenharmony_ciusing IRBuilderTest = ::testing::Test;
34fd4e5da5Sopenharmony_ci
35fd4e5da5Sopenharmony_cibool Validate(const std::vector<uint32_t>& bin) {
36fd4e5da5Sopenharmony_ci  spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
37fd4e5da5Sopenharmony_ci  spv_context spvContext = spvContextCreate(target_env);
38fd4e5da5Sopenharmony_ci  spv_diagnostic diagnostic = nullptr;
39fd4e5da5Sopenharmony_ci  spv_const_binary_t binary = {bin.data(), bin.size()};
40fd4e5da5Sopenharmony_ci  spv_result_t error = spvValidate(spvContext, &binary, &diagnostic);
41fd4e5da5Sopenharmony_ci  if (error != 0) spvDiagnosticPrint(diagnostic);
42fd4e5da5Sopenharmony_ci  spvDiagnosticDestroy(diagnostic);
43fd4e5da5Sopenharmony_ci  spvContextDestroy(spvContext);
44fd4e5da5Sopenharmony_ci  return error == 0;
45fd4e5da5Sopenharmony_ci}
46fd4e5da5Sopenharmony_ci
47fd4e5da5Sopenharmony_civoid Match(const std::string& original, IRContext* context,
48fd4e5da5Sopenharmony_ci           bool do_validation = true) {
49fd4e5da5Sopenharmony_ci  std::vector<uint32_t> bin;
50fd4e5da5Sopenharmony_ci  context->module()->ToBinary(&bin, true);
51fd4e5da5Sopenharmony_ci  if (do_validation) {
52fd4e5da5Sopenharmony_ci    EXPECT_TRUE(Validate(bin));
53fd4e5da5Sopenharmony_ci  }
54fd4e5da5Sopenharmony_ci  std::string assembly;
55fd4e5da5Sopenharmony_ci  SpirvTools tools(SPV_ENV_UNIVERSAL_1_2);
56fd4e5da5Sopenharmony_ci  EXPECT_TRUE(
57fd4e5da5Sopenharmony_ci      tools.Disassemble(bin, &assembly, SpirvTools::kDefaultDisassembleOption))
58fd4e5da5Sopenharmony_ci      << "Disassembling failed for shader:\n"
59fd4e5da5Sopenharmony_ci      << assembly << std::endl;
60fd4e5da5Sopenharmony_ci  auto match_result = effcee::Match(assembly, original);
61fd4e5da5Sopenharmony_ci  EXPECT_EQ(effcee::Result::Status::Ok, match_result.status())
62fd4e5da5Sopenharmony_ci      << match_result.message() << "\nChecking result:\n"
63fd4e5da5Sopenharmony_ci      << assembly;
64fd4e5da5Sopenharmony_ci}
65fd4e5da5Sopenharmony_ci
66fd4e5da5Sopenharmony_ciTEST_F(IRBuilderTest, TestInsnAddition) {
67fd4e5da5Sopenharmony_ci  const std::string text = R"(
68fd4e5da5Sopenharmony_ci; CHECK: %18 = OpLabel
69fd4e5da5Sopenharmony_ci; CHECK: OpPhi %int %int_0 %14
70fd4e5da5Sopenharmony_ci; CHECK: OpPhi %bool %16 %14
71fd4e5da5Sopenharmony_ci; CHECK: OpBranch %17
72fd4e5da5Sopenharmony_ci               OpCapability Shader
73fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
74fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
75fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main" %3
76fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
77fd4e5da5Sopenharmony_ci               OpSource GLSL 330
78fd4e5da5Sopenharmony_ci               OpName %2 "main"
79fd4e5da5Sopenharmony_ci               OpName %4 "i"
80fd4e5da5Sopenharmony_ci               OpName %3 "c"
81fd4e5da5Sopenharmony_ci               OpDecorate %3 Location 0
82fd4e5da5Sopenharmony_ci          %5 = OpTypeVoid
83fd4e5da5Sopenharmony_ci          %6 = OpTypeFunction %5
84fd4e5da5Sopenharmony_ci          %7 = OpTypeInt 32 1
85fd4e5da5Sopenharmony_ci          %8 = OpTypePointer Function %7
86fd4e5da5Sopenharmony_ci          %9 = OpConstant %7 0
87fd4e5da5Sopenharmony_ci         %10 = OpTypeBool
88fd4e5da5Sopenharmony_ci         %11 = OpTypeFloat 32
89fd4e5da5Sopenharmony_ci         %12 = OpTypeVector %11 4
90fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Output %12
91fd4e5da5Sopenharmony_ci          %3 = OpVariable %13 Output
92fd4e5da5Sopenharmony_ci          %2 = OpFunction %5 None %6
93fd4e5da5Sopenharmony_ci         %14 = OpLabel
94fd4e5da5Sopenharmony_ci          %4 = OpVariable %8 Function
95fd4e5da5Sopenharmony_ci               OpStore %4 %9
96fd4e5da5Sopenharmony_ci         %15 = OpLoad %7 %4
97fd4e5da5Sopenharmony_ci         %16 = OpINotEqual %10 %15 %9
98fd4e5da5Sopenharmony_ci               OpSelectionMerge %17 None
99fd4e5da5Sopenharmony_ci               OpBranchConditional %16 %18 %17
100fd4e5da5Sopenharmony_ci         %18 = OpLabel
101fd4e5da5Sopenharmony_ci               OpBranch %17
102fd4e5da5Sopenharmony_ci         %17 = OpLabel
103fd4e5da5Sopenharmony_ci               OpReturn
104fd4e5da5Sopenharmony_ci               OpFunctionEnd
105fd4e5da5Sopenharmony_ci)";
106fd4e5da5Sopenharmony_ci
107fd4e5da5Sopenharmony_ci  {
108fd4e5da5Sopenharmony_ci    std::unique_ptr<IRContext> context =
109fd4e5da5Sopenharmony_ci        BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
110fd4e5da5Sopenharmony_ci
111fd4e5da5Sopenharmony_ci    BasicBlock* bb = context->cfg()->block(18);
112fd4e5da5Sopenharmony_ci
113fd4e5da5Sopenharmony_ci    // Build managers.
114fd4e5da5Sopenharmony_ci    context->get_def_use_mgr();
115fd4e5da5Sopenharmony_ci    context->get_instr_block(nullptr);
116fd4e5da5Sopenharmony_ci
117fd4e5da5Sopenharmony_ci    InstructionBuilder builder(context.get(), &*bb->begin());
118fd4e5da5Sopenharmony_ci    Instruction* phi1 = builder.AddPhi(7, {9, 14});
119fd4e5da5Sopenharmony_ci    Instruction* phi2 = builder.AddPhi(10, {16, 14});
120fd4e5da5Sopenharmony_ci
121fd4e5da5Sopenharmony_ci    // Make sure the InstructionBuilder did not update the def/use manager.
122fd4e5da5Sopenharmony_ci    EXPECT_EQ(context->get_def_use_mgr()->GetDef(phi1->result_id()), nullptr);
123fd4e5da5Sopenharmony_ci    EXPECT_EQ(context->get_def_use_mgr()->GetDef(phi2->result_id()), nullptr);
124fd4e5da5Sopenharmony_ci    EXPECT_EQ(context->get_instr_block(phi1), nullptr);
125fd4e5da5Sopenharmony_ci    EXPECT_EQ(context->get_instr_block(phi2), nullptr);
126fd4e5da5Sopenharmony_ci
127fd4e5da5Sopenharmony_ci    Match(text, context.get());
128fd4e5da5Sopenharmony_ci  }
129fd4e5da5Sopenharmony_ci
130fd4e5da5Sopenharmony_ci  {
131fd4e5da5Sopenharmony_ci    std::unique_ptr<IRContext> context =
132fd4e5da5Sopenharmony_ci        BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
133fd4e5da5Sopenharmony_ci
134fd4e5da5Sopenharmony_ci    // Build managers.
135fd4e5da5Sopenharmony_ci    context->get_def_use_mgr();
136fd4e5da5Sopenharmony_ci    context->get_instr_block(nullptr);
137fd4e5da5Sopenharmony_ci
138fd4e5da5Sopenharmony_ci    BasicBlock* bb = context->cfg()->block(18);
139fd4e5da5Sopenharmony_ci    InstructionBuilder builder(
140fd4e5da5Sopenharmony_ci        context.get(), &*bb->begin(),
141fd4e5da5Sopenharmony_ci        IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
142fd4e5da5Sopenharmony_ci    Instruction* phi1 = builder.AddPhi(7, {9, 14});
143fd4e5da5Sopenharmony_ci    Instruction* phi2 = builder.AddPhi(10, {16, 14});
144fd4e5da5Sopenharmony_ci
145fd4e5da5Sopenharmony_ci    // Make sure InstructionBuilder updated the def/use manager
146fd4e5da5Sopenharmony_ci    EXPECT_NE(context->get_def_use_mgr()->GetDef(phi1->result_id()), nullptr);
147fd4e5da5Sopenharmony_ci    EXPECT_NE(context->get_def_use_mgr()->GetDef(phi2->result_id()), nullptr);
148fd4e5da5Sopenharmony_ci    EXPECT_NE(context->get_instr_block(phi1), nullptr);
149fd4e5da5Sopenharmony_ci    EXPECT_NE(context->get_instr_block(phi2), nullptr);
150fd4e5da5Sopenharmony_ci
151fd4e5da5Sopenharmony_ci    Match(text, context.get());
152fd4e5da5Sopenharmony_ci  }
153fd4e5da5Sopenharmony_ci}
154fd4e5da5Sopenharmony_ci
155fd4e5da5Sopenharmony_ciTEST_F(IRBuilderTest, TestCondBranchAddition) {
156fd4e5da5Sopenharmony_ci  const std::string text = R"(
157fd4e5da5Sopenharmony_ci; CHECK: %main = OpFunction %void None %6
158fd4e5da5Sopenharmony_ci; CHECK-NEXT: %15 = OpLabel
159fd4e5da5Sopenharmony_ci; CHECK-NEXT: OpSelectionMerge %13 None
160fd4e5da5Sopenharmony_ci; CHECK-NEXT: OpBranchConditional %true %14 %13
161fd4e5da5Sopenharmony_ci; CHECK-NEXT: %14 = OpLabel
162fd4e5da5Sopenharmony_ci; CHECK-NEXT: OpBranch %13
163fd4e5da5Sopenharmony_ci; CHECK-NEXT: %13 = OpLabel
164fd4e5da5Sopenharmony_ci; CHECK-NEXT: OpReturn
165fd4e5da5Sopenharmony_ci               OpCapability Shader
166fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
167fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
168fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main" %3
169fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
170fd4e5da5Sopenharmony_ci               OpSource GLSL 330
171fd4e5da5Sopenharmony_ci               OpName %2 "main"
172fd4e5da5Sopenharmony_ci               OpName %4 "i"
173fd4e5da5Sopenharmony_ci               OpName %3 "c"
174fd4e5da5Sopenharmony_ci               OpDecorate %3 Location 0
175fd4e5da5Sopenharmony_ci          %5 = OpTypeVoid
176fd4e5da5Sopenharmony_ci          %6 = OpTypeFunction %5
177fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
178fd4e5da5Sopenharmony_ci          %8 = OpTypePointer Private %7
179fd4e5da5Sopenharmony_ci          %9 = OpConstantTrue %7
180fd4e5da5Sopenharmony_ci         %10 = OpTypeFloat 32
181fd4e5da5Sopenharmony_ci         %11 = OpTypeVector %10 4
182fd4e5da5Sopenharmony_ci         %12 = OpTypePointer Output %11
183fd4e5da5Sopenharmony_ci          %3 = OpVariable %12 Output
184fd4e5da5Sopenharmony_ci          %4 = OpVariable %8 Private
185fd4e5da5Sopenharmony_ci          %2 = OpFunction %5 None %6
186fd4e5da5Sopenharmony_ci         %13 = OpLabel
187fd4e5da5Sopenharmony_ci               OpReturn
188fd4e5da5Sopenharmony_ci               OpFunctionEnd
189fd4e5da5Sopenharmony_ci)";
190fd4e5da5Sopenharmony_ci
191fd4e5da5Sopenharmony_ci  {
192fd4e5da5Sopenharmony_ci    std::unique_ptr<IRContext> context =
193fd4e5da5Sopenharmony_ci        BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
194fd4e5da5Sopenharmony_ci
195fd4e5da5Sopenharmony_ci    Function& fn = *context->module()->begin();
196fd4e5da5Sopenharmony_ci
197fd4e5da5Sopenharmony_ci    BasicBlock& bb_merge = *fn.begin();
198fd4e5da5Sopenharmony_ci
199fd4e5da5Sopenharmony_ci    // TODO(1841): Handle id overflow.
200fd4e5da5Sopenharmony_ci    fn.begin().InsertBefore(std::unique_ptr<BasicBlock>(
201fd4e5da5Sopenharmony_ci        new BasicBlock(std::unique_ptr<Instruction>(new Instruction(
202fd4e5da5Sopenharmony_ci            context.get(), spv::Op::OpLabel, 0, context->TakeNextId(), {})))));
203fd4e5da5Sopenharmony_ci    BasicBlock& bb_true = *fn.begin();
204fd4e5da5Sopenharmony_ci    {
205fd4e5da5Sopenharmony_ci      InstructionBuilder builder(context.get(), &*bb_true.begin());
206fd4e5da5Sopenharmony_ci      builder.AddBranch(bb_merge.id());
207fd4e5da5Sopenharmony_ci    }
208fd4e5da5Sopenharmony_ci
209fd4e5da5Sopenharmony_ci    // TODO(1841): Handle id overflow.
210fd4e5da5Sopenharmony_ci    fn.begin().InsertBefore(std::unique_ptr<BasicBlock>(
211fd4e5da5Sopenharmony_ci        new BasicBlock(std::unique_ptr<Instruction>(new Instruction(
212fd4e5da5Sopenharmony_ci            context.get(), spv::Op::OpLabel, 0, context->TakeNextId(), {})))));
213fd4e5da5Sopenharmony_ci    BasicBlock& bb_cond = *fn.begin();
214fd4e5da5Sopenharmony_ci
215fd4e5da5Sopenharmony_ci    InstructionBuilder builder(context.get(), &bb_cond);
216fd4e5da5Sopenharmony_ci    // This also test consecutive instruction insertion: merge selection +
217fd4e5da5Sopenharmony_ci    // branch.
218fd4e5da5Sopenharmony_ci    builder.AddConditionalBranch(9, bb_true.id(), bb_merge.id(), bb_merge.id());
219fd4e5da5Sopenharmony_ci
220fd4e5da5Sopenharmony_ci    Match(text, context.get());
221fd4e5da5Sopenharmony_ci  }
222fd4e5da5Sopenharmony_ci}
223fd4e5da5Sopenharmony_ci
224fd4e5da5Sopenharmony_ciTEST_F(IRBuilderTest, AddSelect) {
225fd4e5da5Sopenharmony_ci  const std::string text = R"(
226fd4e5da5Sopenharmony_ci; CHECK: [[bool:%\w+]] = OpTypeBool
227fd4e5da5Sopenharmony_ci; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
228fd4e5da5Sopenharmony_ci; CHECK: [[true:%\w+]] = OpConstantTrue [[bool]]
229fd4e5da5Sopenharmony_ci; CHECK: [[u0:%\w+]] = OpConstant [[uint]] 0
230fd4e5da5Sopenharmony_ci; CHECK: [[u1:%\w+]] = OpConstant [[uint]] 1
231fd4e5da5Sopenharmony_ci; CHECK: OpSelect [[uint]] [[true]] [[u0]] [[u1]]
232fd4e5da5Sopenharmony_ciOpCapability Kernel
233fd4e5da5Sopenharmony_ciOpCapability Linkage
234fd4e5da5Sopenharmony_ciOpMemoryModel Logical OpenCL
235fd4e5da5Sopenharmony_ci%1 = OpTypeVoid
236fd4e5da5Sopenharmony_ci%2 = OpTypeBool
237fd4e5da5Sopenharmony_ci%3 = OpTypeInt 32 0
238fd4e5da5Sopenharmony_ci%4 = OpConstantTrue %2
239fd4e5da5Sopenharmony_ci%5 = OpConstant %3 0
240fd4e5da5Sopenharmony_ci%6 = OpConstant %3 1
241fd4e5da5Sopenharmony_ci%7 = OpTypeFunction %1
242fd4e5da5Sopenharmony_ci%8 = OpFunction %1 None %7
243fd4e5da5Sopenharmony_ci%9 = OpLabel
244fd4e5da5Sopenharmony_ciOpReturn
245fd4e5da5Sopenharmony_ciOpFunctionEnd
246fd4e5da5Sopenharmony_ci)";
247fd4e5da5Sopenharmony_ci
248fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
249fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
250fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, context);
251fd4e5da5Sopenharmony_ci
252fd4e5da5Sopenharmony_ci  InstructionBuilder builder(context.get(),
253fd4e5da5Sopenharmony_ci                             &*context->module()->begin()->begin()->begin());
254fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, builder.AddSelect(3u, 4u, 5u, 6u));
255fd4e5da5Sopenharmony_ci
256fd4e5da5Sopenharmony_ci  Match(text, context.get());
257fd4e5da5Sopenharmony_ci}
258fd4e5da5Sopenharmony_ci
259fd4e5da5Sopenharmony_ciTEST_F(IRBuilderTest, AddCompositeConstruct) {
260fd4e5da5Sopenharmony_ci  const std::string text = R"(
261fd4e5da5Sopenharmony_ci; CHECK: [[uint:%\w+]] = OpTypeInt
262fd4e5da5Sopenharmony_ci; CHECK: [[u0:%\w+]] = OpConstant [[uint]] 0
263fd4e5da5Sopenharmony_ci; CHECK: [[u1:%\w+]] = OpConstant [[uint]] 1
264fd4e5da5Sopenharmony_ci; CHECK: [[struct:%\w+]] = OpTypeStruct [[uint]] [[uint]] [[uint]] [[uint]]
265fd4e5da5Sopenharmony_ci; CHECK: OpCompositeConstruct [[struct]] [[u0]] [[u1]] [[u1]] [[u0]]
266fd4e5da5Sopenharmony_ciOpCapability Kernel
267fd4e5da5Sopenharmony_ciOpCapability Linkage
268fd4e5da5Sopenharmony_ciOpMemoryModel Logical OpenCL
269fd4e5da5Sopenharmony_ci%1 = OpTypeVoid
270fd4e5da5Sopenharmony_ci%2 = OpTypeInt 32 0
271fd4e5da5Sopenharmony_ci%3 = OpConstant %2 0
272fd4e5da5Sopenharmony_ci%4 = OpConstant %2 1
273fd4e5da5Sopenharmony_ci%5 = OpTypeStruct %2 %2 %2 %2
274fd4e5da5Sopenharmony_ci%6 = OpTypeFunction %1
275fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %6
276fd4e5da5Sopenharmony_ci%8 = OpLabel
277fd4e5da5Sopenharmony_ciOpReturn
278fd4e5da5Sopenharmony_ciOpFunctionEnd
279fd4e5da5Sopenharmony_ci)";
280fd4e5da5Sopenharmony_ci
281fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
282fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
283fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, context);
284fd4e5da5Sopenharmony_ci
285fd4e5da5Sopenharmony_ci  InstructionBuilder builder(context.get(),
286fd4e5da5Sopenharmony_ci                             &*context->module()->begin()->begin()->begin());
287fd4e5da5Sopenharmony_ci  std::vector<uint32_t> ids = {3u, 4u, 4u, 3u};
288fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, builder.AddCompositeConstruct(5u, ids));
289fd4e5da5Sopenharmony_ci
290fd4e5da5Sopenharmony_ci  Match(text, context.get());
291fd4e5da5Sopenharmony_ci}
292fd4e5da5Sopenharmony_ci
293fd4e5da5Sopenharmony_ciTEST_F(IRBuilderTest, ConstantAdder) {
294fd4e5da5Sopenharmony_ci  const std::string text = R"(
295fd4e5da5Sopenharmony_ci; CHECK: [[uint:%\w+]] = OpTypeInt 32 0
296fd4e5da5Sopenharmony_ci; CHECK: OpConstant [[uint]] 13
297fd4e5da5Sopenharmony_ci; CHECK: [[sint:%\w+]] = OpTypeInt 32 1
298fd4e5da5Sopenharmony_ci; CHECK: OpConstant [[sint]] -1
299fd4e5da5Sopenharmony_ci; CHECK: OpConstant [[uint]] 1
300fd4e5da5Sopenharmony_ci; CHECK: OpConstant [[sint]] 34
301fd4e5da5Sopenharmony_ci; CHECK: OpConstant [[uint]] 0
302fd4e5da5Sopenharmony_ci; CHECK: OpConstant [[sint]] 0
303fd4e5da5Sopenharmony_ciOpCapability Shader
304fd4e5da5Sopenharmony_ciOpCapability Linkage
305fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
306fd4e5da5Sopenharmony_ci%1 = OpTypeVoid
307fd4e5da5Sopenharmony_ci%2 = OpTypeFunction %1
308fd4e5da5Sopenharmony_ci%3 = OpFunction %1 None %2
309fd4e5da5Sopenharmony_ci%4 = OpLabel
310fd4e5da5Sopenharmony_ciOpReturn
311fd4e5da5Sopenharmony_ciOpFunctionEnd
312fd4e5da5Sopenharmony_ci)";
313fd4e5da5Sopenharmony_ci
314fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
315fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
316fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, context);
317fd4e5da5Sopenharmony_ci
318fd4e5da5Sopenharmony_ci  InstructionBuilder builder(context.get(),
319fd4e5da5Sopenharmony_ci                             &*context->module()->begin()->begin()->begin());
320fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, builder.GetUintConstant(13));
321fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, builder.GetSintConstant(-1));
322fd4e5da5Sopenharmony_ci
323fd4e5da5Sopenharmony_ci  // Try adding the same constants again to make sure they aren't added.
324fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, builder.GetUintConstant(13));
325fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, builder.GetSintConstant(-1));
326fd4e5da5Sopenharmony_ci
327fd4e5da5Sopenharmony_ci  // Try adding different constants to make sure the type is reused.
328fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, builder.GetUintConstant(1));
329fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, builder.GetSintConstant(34));
330fd4e5da5Sopenharmony_ci
331fd4e5da5Sopenharmony_ci  // Try adding 0 as both signed and unsigned.
332fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, builder.GetUintConstant(0));
333fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, builder.GetSintConstant(0));
334fd4e5da5Sopenharmony_ci
335fd4e5da5Sopenharmony_ci  Match(text, context.get());
336fd4e5da5Sopenharmony_ci}
337fd4e5da5Sopenharmony_ci
338fd4e5da5Sopenharmony_ciTEST_F(IRBuilderTest, ConstantAdderTypeAlreadyExists) {
339fd4e5da5Sopenharmony_ci  const std::string text = R"(
340fd4e5da5Sopenharmony_ci; CHECK: OpConstant %uint 13
341fd4e5da5Sopenharmony_ci; CHECK: OpConstant %int -1
342fd4e5da5Sopenharmony_ci; CHECK: OpConstant %uint 1
343fd4e5da5Sopenharmony_ci; CHECK: OpConstant %int 34
344fd4e5da5Sopenharmony_ci; CHECK: OpConstant %uint 0
345fd4e5da5Sopenharmony_ci; CHECK: OpConstant %int 0
346fd4e5da5Sopenharmony_ciOpCapability Shader
347fd4e5da5Sopenharmony_ciOpCapability Linkage
348fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
349fd4e5da5Sopenharmony_ci%1 = OpTypeVoid
350fd4e5da5Sopenharmony_ci%uint = OpTypeInt 32 0
351fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 1
352fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1
353fd4e5da5Sopenharmony_ci%5 = OpFunction %1 None %4
354fd4e5da5Sopenharmony_ci%6 = OpLabel
355fd4e5da5Sopenharmony_ciOpReturn
356fd4e5da5Sopenharmony_ciOpFunctionEnd
357fd4e5da5Sopenharmony_ci)";
358fd4e5da5Sopenharmony_ci
359fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
360fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
361fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, context);
362fd4e5da5Sopenharmony_ci
363fd4e5da5Sopenharmony_ci  InstructionBuilder builder(context.get(),
364fd4e5da5Sopenharmony_ci                             &*context->module()->begin()->begin()->begin());
365fd4e5da5Sopenharmony_ci  Instruction* const_1 = builder.GetUintConstant(13);
366fd4e5da5Sopenharmony_ci  Instruction* const_2 = builder.GetSintConstant(-1);
367fd4e5da5Sopenharmony_ci
368fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, const_1);
369fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, const_2);
370fd4e5da5Sopenharmony_ci
371fd4e5da5Sopenharmony_ci  // Try adding the same constants again to make sure they aren't added.
372fd4e5da5Sopenharmony_ci  EXPECT_EQ(const_1, builder.GetUintConstant(13));
373fd4e5da5Sopenharmony_ci  EXPECT_EQ(const_2, builder.GetSintConstant(-1));
374fd4e5da5Sopenharmony_ci
375fd4e5da5Sopenharmony_ci  Instruction* const_3 = builder.GetUintConstant(1);
376fd4e5da5Sopenharmony_ci  Instruction* const_4 = builder.GetSintConstant(34);
377fd4e5da5Sopenharmony_ci
378fd4e5da5Sopenharmony_ci  // Try adding different constants to make sure the type is reused.
379fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, const_3);
380fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, const_4);
381fd4e5da5Sopenharmony_ci
382fd4e5da5Sopenharmony_ci  Instruction* const_5 = builder.GetUintConstant(0);
383fd4e5da5Sopenharmony_ci  Instruction* const_6 = builder.GetSintConstant(0);
384fd4e5da5Sopenharmony_ci
385fd4e5da5Sopenharmony_ci  // Try adding 0 as both signed and unsigned.
386fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, const_5);
387fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, const_6);
388fd4e5da5Sopenharmony_ci
389fd4e5da5Sopenharmony_ci  // They have the same value but different types so should be unique.
390fd4e5da5Sopenharmony_ci  EXPECT_NE(const_5, const_6);
391fd4e5da5Sopenharmony_ci
392fd4e5da5Sopenharmony_ci  // Check the types are correct.
393fd4e5da5Sopenharmony_ci  uint32_t type_id_unsigned = const_1->GetSingleWordOperand(0);
394fd4e5da5Sopenharmony_ci  uint32_t type_id_signed = const_2->GetSingleWordOperand(0);
395fd4e5da5Sopenharmony_ci
396fd4e5da5Sopenharmony_ci  EXPECT_NE(type_id_unsigned, type_id_signed);
397fd4e5da5Sopenharmony_ci
398fd4e5da5Sopenharmony_ci  EXPECT_EQ(const_3->GetSingleWordOperand(0), type_id_unsigned);
399fd4e5da5Sopenharmony_ci  EXPECT_EQ(const_5->GetSingleWordOperand(0), type_id_unsigned);
400fd4e5da5Sopenharmony_ci
401fd4e5da5Sopenharmony_ci  EXPECT_EQ(const_4->GetSingleWordOperand(0), type_id_signed);
402fd4e5da5Sopenharmony_ci  EXPECT_EQ(const_6->GetSingleWordOperand(0), type_id_signed);
403fd4e5da5Sopenharmony_ci
404fd4e5da5Sopenharmony_ci  Match(text, context.get());
405fd4e5da5Sopenharmony_ci}
406fd4e5da5Sopenharmony_ci
407fd4e5da5Sopenharmony_ciTEST_F(IRBuilderTest, AccelerationStructureNV) {
408fd4e5da5Sopenharmony_ci  const std::string text = R"(
409fd4e5da5Sopenharmony_ci; CHECK: OpTypeAccelerationStructureKHR
410fd4e5da5Sopenharmony_ciOpCapability Shader
411fd4e5da5Sopenharmony_ciOpCapability RayTracingNV
412fd4e5da5Sopenharmony_ciOpExtension "SPV_NV_ray_tracing"
413fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450
414fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %8 "main"
415fd4e5da5Sopenharmony_ciOpExecutionMode %8 OriginUpperLeft
416fd4e5da5Sopenharmony_ci%1 = OpTypeVoid
417fd4e5da5Sopenharmony_ci%2 = OpTypeBool
418fd4e5da5Sopenharmony_ci%3 = OpTypeAccelerationStructureNV
419fd4e5da5Sopenharmony_ci%7 = OpTypeFunction %1
420fd4e5da5Sopenharmony_ci%8 = OpFunction %1 None %7
421fd4e5da5Sopenharmony_ci%9 = OpLabel
422fd4e5da5Sopenharmony_ciOpReturn
423fd4e5da5Sopenharmony_ciOpFunctionEnd
424fd4e5da5Sopenharmony_ci)";
425fd4e5da5Sopenharmony_ci
426fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
427fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
428fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, context);
429fd4e5da5Sopenharmony_ci
430fd4e5da5Sopenharmony_ci  InstructionBuilder builder(context.get(),
431fd4e5da5Sopenharmony_ci                             &*context->module()->begin()->begin()->begin());
432fd4e5da5Sopenharmony_ci  Match(text, context.get());
433fd4e5da5Sopenharmony_ci}
434fd4e5da5Sopenharmony_ci
435fd4e5da5Sopenharmony_ci}  // namespace
436fd4e5da5Sopenharmony_ci}  // namespace opt
437fd4e5da5Sopenharmony_ci}  // namespace spvtools
438