1de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar//=====- CFLSummary.h - Abstract stratified sets implementation. --------=====//
2de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar//
3de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar//                     The LLVM Compiler Infrastructure
4de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar//
5de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar// This file is distributed under the University of Illinois Open Source
6de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar// License. See LICENSE.TXT for details.
7de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar//
8de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar//===----------------------------------------------------------------------===//
9de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// \file
10de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// This file defines various utility types and functions useful to
11de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// summary-based alias analysis.
12de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar///
13de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// Summary-based analysis, also known as bottom-up analysis, is a style of
14de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// interprocedrual static analysis that tries to analyze the callees before the
15de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// callers get analyzed. The key idea of summary-based analysis is to first
16de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// process each function indepedently, outline its behavior in a condensed
17de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// summary, and then instantiate the summary at the callsite when the said
18de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// function is called elsewhere. This is often in contrast to another style
19de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// called top-down analysis, in which callers are always analyzed first before
20de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// the callees.
21de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar///
22de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// In a summary-based analysis, functions must be examined independently and
23de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// out-of-context. We have no information on the state of the memory, the
24de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// arguments, the global values, and anything else external to the function. To
25de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// carry out the analysis conservative assumptions have to be made about those
26de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// external states. In exchange for the potential loss of precision, the
27de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// summary we obtain this way is highly reusable, which makes the analysis
28de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// easier to scale to large programs even if carried out context-sensitively.
29de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar///
30de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// Currently, all CFL-based alias analyses adopt the summary-based approach
31de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// and therefore heavily rely on this header.
32de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar///
33de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar//===----------------------------------------------------------------------===//
34de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
35de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar#ifndef LLVM_ANALYSIS_ALIASANALYSISSUMMARY_H
36de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar#define LLVM_ANALYSIS_ALIASANALYSISSUMMARY_H
37de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
38de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar#include "llvm/ADT/DenseMapInfo.h"
39de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar#include "llvm/ADT/Optional.h"
40de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar#include "llvm/ADT/SmallVector.h"
41de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar#include "llvm/IR/CallSite.h"
42de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar#include <bitset>
43de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
44de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarnamespace llvm {
45de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarnamespace cflaa {
46de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
47de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar//===----------------------------------------------------------------------===//
48de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar// AliasAttr related stuffs
49de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar//===----------------------------------------------------------------------===//
50de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
51de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// The number of attributes that AliasAttr should contain. Attributes are
52de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// described below, and 32 was an arbitrary choice because it fits nicely in 32
53de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// bits (because we use a bitset for AliasAttr).
54de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarstatic const unsigned NumAliasAttrs = 32;
55de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
56de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// These are attributes that an alias analysis can use to mark certain special
57de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// properties of a given pointer. Refer to the related functions below to see
58de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// what kinds of attributes are currently defined.
59de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainartypedef std::bitset<NumAliasAttrs> AliasAttrs;
60de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
61de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// Attr represent whether the said pointer comes from an unknown source
62de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// (such as opaque memory or an integer cast).
63de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga NainarAliasAttrs getAttrNone();
64de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
65de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// AttrUnknown represent whether the said pointer comes from a source not known
66de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// to alias analyses (such as opaque memory or an integer cast).
67de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga NainarAliasAttrs getAttrUnknown();
68de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarbool hasUnknownAttr(AliasAttrs);
69de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
70de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// AttrCaller represent whether the said pointer comes from a source not known
71de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// to the current function but known to the caller. Values pointed to by the
72de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// arguments of the current function have this attribute set
73de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga NainarAliasAttrs getAttrCaller();
74de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarbool hasCallerAttr(AliasAttrs);
75de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarbool hasUnknownOrCallerAttr(AliasAttrs);
76de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
77de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// AttrEscaped represent whether the said pointer comes from a known source but
78de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// escapes to the unknown world (e.g. casted to an integer, or passed as an
79de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// argument to opaque function). Unlike non-escaped pointers, escaped ones may
80de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// alias pointers coming from unknown sources.
81de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga NainarAliasAttrs getAttrEscaped();
82de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarbool hasEscapedAttr(AliasAttrs);
83de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
84de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// AttrGlobal represent whether the said pointer is a global value.
85de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// AttrArg represent whether the said pointer is an argument, and if so, what
86de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// index the argument has.
87de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga NainarAliasAttrs getGlobalOrArgAttrFromValue(const Value &);
88de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarbool isGlobalOrArgAttr(AliasAttrs);
89de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
90de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// Given an AliasAttrs, return a new AliasAttrs that only contains attributes
91de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// meaningful to the caller. This function is primarily used for
92de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// interprocedural analysis
93de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// Currently, externally visible AliasAttrs include AttrUnknown, AttrGlobal,
94de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// and AttrEscaped
95de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga NainarAliasAttrs getExternallyVisibleAttrs(AliasAttrs);
96de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
97de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar//===----------------------------------------------------------------------===//
98de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar// Function summary related stuffs
99de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar//===----------------------------------------------------------------------===//
100de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
101de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// The maximum number of arguments we can put into a summary.
102de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga NainarLLVM_CONSTEXPR static unsigned MaxSupportedArgsInSummary = 50;
103de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
104de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// We use InterfaceValue to describe parameters/return value, as well as
105de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// potential memory locations that are pointed to by parameters/return value,
106de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// of a function.
107de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// Index is an integer which represents a single parameter or a return value.
108de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// When the index is 0, it refers to the return value. Non-zero index i refers
109de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// to the i-th parameter.
110de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// DerefLevel indicates the number of dereferences one must perform on the
111de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// parameter/return value to get this InterfaceValue.
112de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarstruct InterfaceValue {
113de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  unsigned Index;
114de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  unsigned DerefLevel;
115de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar};
116de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
117de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarinline bool operator==(InterfaceValue lhs, InterfaceValue rhs) {
118de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  return lhs.Index == rhs.Index && lhs.DerefLevel == rhs.DerefLevel;
119de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar}
120de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarinline bool operator!=(InterfaceValue lhs, InterfaceValue rhs) {
121de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  return !(lhs == rhs);
122de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar}
123de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
124de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// We use ExternalRelation to describe an externally visible aliasing relations
125de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// between parameters/return value of a function.
126de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarstruct ExternalRelation {
127de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  InterfaceValue From, To;
128de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar};
129de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
130de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// We use ExternalAttribute to describe an externally visible AliasAttrs
131de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// for parameters/return value.
132de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarstruct ExternalAttribute {
133de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  InterfaceValue IValue;
134de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  AliasAttrs Attr;
135de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar};
136de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
137de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// AliasSummary is just a collection of ExternalRelation and ExternalAttribute
138de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarstruct AliasSummary {
139de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  // RetParamRelations is a collection of ExternalRelations.
140de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  SmallVector<ExternalRelation, 8> RetParamRelations;
141de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
142de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  // RetParamAttributes is a collection of ExternalAttributes.
143de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  SmallVector<ExternalAttribute, 8> RetParamAttributes;
144de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar};
145de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
146de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// This is the result of instantiating InterfaceValue at a particular callsite
147de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarstruct InstantiatedValue {
148de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  Value *Val;
149de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  unsigned DerefLevel;
150de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar};
151de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga NainarOptional<InstantiatedValue> instantiateInterfaceValue(InterfaceValue, CallSite);
152de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
153de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// This is the result of instantiating ExternalRelation at a particular
154de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// callsite
155de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarstruct InstantiatedRelation {
156de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  InstantiatedValue From, To;
157de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar};
158de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga NainarOptional<InstantiatedRelation> instantiateExternalRelation(ExternalRelation,
159de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar                                                           CallSite);
160de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
161de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// This is the result of instantiating ExternalAttribute at a particular
162de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar/// callsite
163de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarstruct InstantiatedAttr {
164de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  InstantiatedValue IValue;
165de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  AliasAttrs Attr;
166de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar};
167de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga NainarOptional<InstantiatedAttr> instantiateExternalAttribute(ExternalAttribute,
168de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar                                                        CallSite);
169de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar}
170de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
171de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainartemplate <> struct DenseMapInfo<cflaa::InstantiatedValue> {
172de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  static inline cflaa::InstantiatedValue getEmptyKey() {
173de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    return cflaa::InstantiatedValue{DenseMapInfo<Value *>::getEmptyKey(),
174de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar                                    DenseMapInfo<unsigned>::getEmptyKey()};
175de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  }
176de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  static inline cflaa::InstantiatedValue getTombstoneKey() {
177de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    return cflaa::InstantiatedValue{DenseMapInfo<Value *>::getTombstoneKey(),
178de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar                                    DenseMapInfo<unsigned>::getTombstoneKey()};
179de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  }
180de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  static unsigned getHashValue(const cflaa::InstantiatedValue &IV) {
181de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    return DenseMapInfo<std::pair<Value *, unsigned>>::getHashValue(
182de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar        std::make_pair(IV.Val, IV.DerefLevel));
183de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  }
184de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  static bool isEqual(const cflaa::InstantiatedValue &LHS,
185de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar                      const cflaa::InstantiatedValue &RHS) {
186de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    return LHS.Val == RHS.Val && LHS.DerefLevel == RHS.DerefLevel;
187de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  }
188de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar};
189de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar}
190de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
191de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar#endif
192