Skip to content

Commit e741182

Browse files
[CSA] Add CSADescriptors Analysis
1 parent 5b34a9e commit e741182

File tree

3 files changed

+152
-0
lines changed

3 files changed

+152
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//===- llvm/Analysis/CSADescriptors.h - CSA Descriptors --*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file "describes" conditional scalar assignments (CSA).
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "llvm/Analysis/LoopInfo.h"
14+
#include "llvm/IR/Instructions.h"
15+
#include "llvm/IR/Value.h"
16+
17+
#ifndef LLVM_ANALYSIS_CSADESCRIPTORS_H
18+
#define LLVM_ANALYSIS_CSADESCRIPTORS_H
19+
20+
namespace llvm {
21+
22+
/// A Conditional Scalar Assignment (CSA) is an assignment from an initial
23+
/// scalar that may or may not occur.
24+
class CSADescriptor {
25+
/// If the conditional assignment occurs inside a loop, then Phi chooses
26+
/// the value of the assignment from the entry block or the loop body block.
27+
PHINode *Phi = nullptr;
28+
29+
/// The initial value of the CSA. If the condition guarding the assignment is
30+
/// not met, then the assignment retains this value.
31+
Value *InitScalar = nullptr;
32+
33+
/// The Instruction that conditionally assigned to inside the loop.
34+
Instruction *Assignment = nullptr;
35+
36+
/// Create a CSA Descriptor that models an invalid CSA.
37+
CSADescriptor() = default;
38+
39+
/// Create a CSA Descriptor that models a valid CSA with its members
40+
/// initialized correctly.
41+
CSADescriptor(PHINode *Phi, Instruction *Assignment, Value *InitScalar)
42+
: Phi(Phi), InitScalar(InitScalar), Assignment(Assignment) {}
43+
44+
public:
45+
/// If Phi is the root of a CSA, return the CSADescriptor of the CSA rooted by
46+
/// Phi. Otherwise, return a CSADescriptor with IsValidCSA set to false.
47+
static CSADescriptor isCSAPhi(PHINode *Phi, Loop *TheLoop);
48+
49+
operator bool() const { return isValid(); }
50+
51+
/// Returns whether SI is the Assignment in CSA
52+
static bool isCSASelect(CSADescriptor Desc, SelectInst *SI) {
53+
return Desc.getAssignment() == SI;
54+
}
55+
56+
/// Return whether this CSADescriptor models a valid CSA.
57+
bool isValid() const { return Phi && InitScalar && Assignment; }
58+
59+
/// Return the PHI that roots this CSA.
60+
PHINode *getPhi() const { return Phi; }
61+
62+
/// Return the initial value of the CSA. This is the value if the conditional
63+
/// assignment does not occur.
64+
Value *getInitScalar() const { return InitScalar; }
65+
66+
/// The Instruction that is used after the loop
67+
Instruction *getAssignment() const { return Assignment; }
68+
69+
/// Return the condition that this CSA is conditional upon.
70+
Value *getCond() const {
71+
if (auto *SI = dyn_cast_or_null<SelectInst>(Assignment))
72+
return SI->getCondition();
73+
return nullptr;
74+
}
75+
};
76+
} // namespace llvm
77+
78+
#endif // LLVM_ANALYSIS_CSADESCRIPTORS_H

llvm/lib/Analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ add_llvm_component_library(LLVMAnalysis
4646
CostModel.cpp
4747
CodeMetrics.cpp
4848
ConstantFolding.cpp
49+
CSADescriptors.cpp
4950
CtxProfAnalysis.cpp
5051
CycleAnalysis.cpp
5152
DDG.cpp

llvm/lib/Analysis/CSADescriptors.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//=== llvm/Analysis/CSADescriptors.cpp - CSA Descriptors -*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file "describes" conditional scalar assignments (CSA).
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "llvm/Analysis/CSADescriptors.h"
14+
#include "llvm/IR/PatternMatch.h"
15+
#include "llvm/IR/Type.h"
16+
17+
using namespace llvm;
18+
using namespace llvm::PatternMatch;
19+
20+
#define DEBUG_TYPE "csa-descriptors"
21+
22+
CSADescriptor CSADescriptor::isCSAPhi(PHINode *Phi, Loop *TheLoop) {
23+
// Return CSADescriptor that describes a CSA that matches one of these
24+
// patterns:
25+
// phi loop_inv, (select cmp, value, phi)
26+
// phi loop_inv, (select cmp, phi, value)
27+
// phi (select cmp, value, phi), loop_inv
28+
// phi (select cmp, phi, value), loop_inv
29+
// If the CSA does not match any of these paterns, return a CSADescriptor
30+
// that describes an InvalidCSA.
31+
32+
// Must be a scalar
33+
Type *Type = Phi->getType();
34+
if (!Type->isIntegerTy() && !Type->isFloatingPointTy() &&
35+
!Type->isPointerTy())
36+
return CSADescriptor();
37+
38+
// Match phi loop_inv, (select cmp, value, phi)
39+
// or phi loop_inv, (select cmp, phi, value)
40+
// or phi (select cmp, value, phi), loop_inv
41+
// or phi (select cmp, phi, value), loop_inv
42+
if (Phi->getNumIncomingValues() != 2)
43+
return CSADescriptor();
44+
auto SelectInstIt = find_if(Phi->incoming_values(), [&Phi](Use &U) {
45+
return match(U.get(), m_Select(m_Value(), m_Specific(Phi), m_Value())) ||
46+
match(U.get(), m_Select(m_Value(), m_Value(), m_Specific(Phi)));
47+
});
48+
if (SelectInstIt == Phi->incoming_values().end())
49+
return CSADescriptor();
50+
auto LoopInvIt = find_if(Phi->incoming_values(), [&](Use &U) {
51+
return U.get() != *SelectInstIt && TheLoop->isLoopInvariant(U.get());
52+
});
53+
if (LoopInvIt == Phi->incoming_values().end())
54+
return CSADescriptor();
55+
56+
// Phi or Sel must be used only outside the loop,
57+
// excluding if Phi use Sel or Sel use Phi
58+
auto IsOnlyUsedOutsideLoop = [=](Value *V, Value *Ignore) {
59+
return all_of(V->users(), [Ignore, TheLoop](User *U) {
60+
if (U == Ignore)
61+
return true;
62+
if (auto *I = dyn_cast<Instruction>(U))
63+
return !TheLoop->contains(I);
64+
return true;
65+
});
66+
};
67+
auto *Sel = cast<SelectInst>(SelectInstIt->get());
68+
auto *LoopInv = LoopInvIt->get();
69+
if (!IsOnlyUsedOutsideLoop(Phi, Sel) || !IsOnlyUsedOutsideLoop(Sel, Phi))
70+
return CSADescriptor();
71+
72+
return CSADescriptor(Phi, Sel, LoopInv);
73+
}

0 commit comments

Comments
 (0)