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