blob: 29e2654a77c4b7dab4149ae4a5dc0c85ca4187bf [file] [log] [blame]
Alan Baker33376ea2018-08-30 12:02:31 -04001// Copyright 2018 The Clspv 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#include <vector>
16
17#include "llvm/ADT/SmallVector.h"
18#include "llvm/IR/BasicBlock.h"
19#include "llvm/IR/Instructions.h"
20#include "llvm/IR/Module.h"
21#include "llvm/Pass.h"
22#include "llvm/Support/raw_ostream.h"
23
24#include "clspv/Option.h"
25
Diego Novilloa4c44fa2019-04-11 10:56:15 -040026#include "Passes.h"
27
Alan Baker33376ea2018-08-30 12:02:31 -040028using namespace llvm;
29
30namespace {
31class ScalarizePass : public ModulePass {
32public:
33 static char ID;
34 ScalarizePass() : ModulePass(ID) {}
35
36 bool runOnModule(Module &M) override;
37
38private:
39 // Breaks a struct type phi down into its constituent elements. It does this
40 // recursively in the event the subtypes are also structs. Returns the
41 // replacement value. Returns the replacment value for the phi.
42 Value *ScalarizePhi(PHINode *phi);
43
44 // Phi nodes that need to be deleted.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040045 std::vector<PHINode *> to_delete_;
Alan Baker33376ea2018-08-30 12:02:31 -040046};
47} // namespace
48
49namespace clspv {
50ModulePass *createScalarizePass() { return new ScalarizePass(); }
51} // namespace clspv
52
53char ScalarizePass::ID = 0;
Diego Novilloa4c44fa2019-04-11 10:56:15 -040054INITIALIZE_PASS(ScalarizePass, "Scalarize",
55 "Scalarizes some instructions with composite returns", false,
56 false)
Alan Baker33376ea2018-08-30 12:02:31 -040057
58bool ScalarizePass::runOnModule(Module &M) {
59 bool Changed = false;
60 for (auto &F : M) {
61 for (auto &BB : F) {
62 for (auto &I : BB) {
63 if (auto *phi = dyn_cast<PHINode>(&I)) {
64 if (clspv::Option::HackPhis() && phi->getType()->isStructTy()) {
65 ScalarizePhi(phi);
66 Changed = true;
67 }
68 }
69 }
70 }
71 }
72
73 for (auto *phi : to_delete_)
74 phi->eraseFromParent();
75
76 return Changed;
77}
78
79Value *ScalarizePass::ScalarizePhi(PHINode *phi) {
80 // Break down all the struct elements of the phi into individual elements and
81 // create new phis for them. Recombine the new phis into a single struct
82 // after the phi instructions.
83 if (!phi->getType()->isStructTy())
84 return phi;
85
86 // Cache the insertion location now. If we break down subtypes, we don't want
87 // to insert uses before definitions.
88 Instruction *where = phi->getParent()->getFirstNonPHI();
89 const auto num_incoming_values = phi->getNumIncomingValues();
90 unsigned type_index = 0;
91 SmallVector<Value *, 16> replacements;
92 for (auto *subtype : phi->getType()->subtypes()) {
93 PHINode *replacement =
94 PHINode::Create(subtype, num_incoming_values, "", phi);
95 for (unsigned i = 0; i != num_incoming_values; ++i) {
96 auto *incoming_block = phi->getIncomingBlock(i);
97 auto *incoming_value = phi->getIncomingValue(i);
98
99 Value *extracted_value = nullptr;
100 if (auto *constant = dyn_cast<Constant>(incoming_value)) {
101 extracted_value = constant->getAggregateElement(type_index);
102 } else {
103 // Extract the value just before the incoming block's branch.
104 extracted_value = ExtractValueInst::Create(
105 incoming_value, {type_index}, "", incoming_block->getTerminator());
106 }
107 replacement->addIncoming(extracted_value, incoming_block);
108 }
109 // Recursively break down subtype structs.
110 replacements.push_back(ScalarizePhi(replacement));
111 ++type_index;
112 }
113
114 // Regenerate the struct just after the phi instructions. Update the
115 // insertion location to aid RewriteInsertsPass.
116 Value *prev = Constant::getNullValue(phi->getType());
117 for (unsigned i = 0; i != replacements.size(); ++i) {
118 where = InsertValueInst::Create(prev, replacements[i], {i}, "", where);
119 prev = where;
120 }
121
122 // Replace the struct phi
123 phi->replaceAllUsesWith(prev);
124 to_delete_.push_back(phi);
125
126 return prev;
127}