14 #include <unordered_map>
17 #include <sys/types.h>
20 #include <semaphore.h>
26 #include <sys/syscall.h>
37 #include <google/sparse_hash_map>
38 #include <google/dense_hash_map>
47 #define PAGE_OFFSET_BITS (16LL)
48 #define PAGE_OFFSET(addr) (addr & 0xFFFF)
49 #define PAGE_OFFSET_MASK (0xFFFF)
54 #define PAGE_SIZE (1 << PAGE_OFFSET_BITS)
57 #define PTR_SIZE (sizeof(void*))
58 #define LEVEL_1_PAGE_TABLE_BITS (20)
59 #define LEVEL_1_PAGE_TABLE_ENTRIES (1 << LEVEL_1_PAGE_TABLE_BITS)
60 #define LEVEL_1_PAGE_TABLE_SIZE (LEVEL_1_PAGE_TABLE_ENTRIES * PTR_SIZE)
62 #define LEVEL_2_PAGE_TABLE_BITS (12)
63 #define LEVEL_2_PAGE_TABLE_ENTRIES (1 << LEVEL_2_PAGE_TABLE_BITS)
64 #define LEVEL_2_PAGE_TABLE_SIZE (LEVEL_2_PAGE_TABLE_ENTRIES * PTR_SIZE)
66 #define LEVEL_1_PAGE_TABLE_SLOT(addr) (((addr) >> (LEVEL_2_PAGE_TABLE_BITS + PAGE_OFFSET_BITS)) & 0xfffff)
67 #define LEVEL_2_PAGE_TABLE_SLOT(addr) (((addr) >> (PAGE_OFFSET_BITS)) & 0xFFF)
71 #define MAX_FILE_PATH (200)
72 #define MAX_DEAD_CONTEXTS_TO_LOG (4000)
73 #define MAX_LOG_NUM (110)
74 #define MAX_OPERAND (6)
75 #define SAMPLE_PERIOD (1000000)
76 #define STOP_PERIOD (1000000000)
104 uint64_t regNumber[REG_LAST];
115 memset(regNumber, 0,
sizeof(uint64_t) * REG_LAST);
139 if (INS_IsFarJump(ins) || INS_IsDirectFarJump(ins) ||
INS_IsMaskedJump(ins))
141 else if (INS_IsRet(ins) || INS_IsIRet(ins))
143 else if (INS_IsCall(ins) || INS_IsSyscall(ins))
145 else if (INS_IsBranch(ins) || INS_IsRDTSC(ins) || INS_IsNop(ins))
153 case XED_ICLASS_MOVAPD:
154 case XED_ICLASS_MOVAPS:
155 case XED_ICLASS_MOVBE:
156 case XED_ICLASS_MOVD:
157 case XED_ICLASS_MOVDDUP:
158 case XED_ICLASS_MOVDQ2Q:
159 case XED_ICLASS_MOVDQA:
160 case XED_ICLASS_MOVDQU:
161 case XED_ICLASS_MOVHLPS:
162 case XED_ICLASS_MOVHPD:
163 case XED_ICLASS_MOVHPS:
164 case XED_ICLASS_MOVLHPS:
165 case XED_ICLASS_MOVLPD:
166 case XED_ICLASS_MOVLPS:
167 case XED_ICLASS_MOVMSKPD:
168 case XED_ICLASS_MOVMSKPS:
169 case XED_ICLASS_MOVNTDQ:
170 case XED_ICLASS_MOVNTDQA:
171 case XED_ICLASS_MOVNTI:
172 case XED_ICLASS_MOVNTPD:
173 case XED_ICLASS_MOVNTPS:
174 case XED_ICLASS_MOVNTQ:
175 case XED_ICLASS_MOVNTSD:
176 case XED_ICLASS_MOVNTSS:
177 case XED_ICLASS_MOVQ:
178 case XED_ICLASS_MOVQ2DQ:
179 case XED_ICLASS_MOVSB:
180 case XED_ICLASS_MOVSD:
181 case XED_ICLASS_MOVSD_XMM:
182 case XED_ICLASS_MOVSHDUP:
183 case XED_ICLASS_MOVSLDUP:
184 case XED_ICLASS_MOVSQ:
185 case XED_ICLASS_MOVSS:
186 case XED_ICLASS_MOVSW:
187 case XED_ICLASS_MOVSX:
188 case XED_ICLASS_MOVSXD:
189 case XED_ICLASS_MOVUPD:
190 case XED_ICLASS_MOVUPS:
191 case XED_ICLASS_MOVZX:
192 case XED_ICLASS_MOV_CR:
193 case XED_ICLASS_MOV_DR:
302 if (*l1Ptr ==
nullptr) {
315 if (*prevAddr == 0) {
367 uint64_t deadIndex = (uint64_t)deadCtxt;
368 uint64_t killerIndex = (uint64_t)killerCtxt;
369 uint64_t key = (deadIndex << 32) | killerIndex;
372 td->
redundantMap.insert(std::pair<uint64_t, uint64_t>(key, 1));
390 uint64_t addr = (uint64_t)
ip;
393 if (*prevAddr == 0) {
394 uint64_t* valueNumIP;
395 valueNumIP = (uint64_t*)malloc(
sizeof(uint64_t) * (
VALUE_N + 1));
396 for (
int i = 0; i <=
VALUE_N; ++i) {
399 valueNumIP[0] = nValue;
400 *prevAddr = (uint64_t)(valueNumIP);
404 valuesIP = (uint64_t*)(*prevAddr);
406 for (i = 0; i <
VALUE_N; ++i) {
407 if (valuesIP[i] == 0) {
408 valuesIP[i] = nValue;
410 }
else if (valuesIP[i] == nValue)
416 uint64_t index = valuesIP[
VALUE_N];
419 uint64_t old = valuesIP[index];
421 valuesIP[index] = nValue;
424 *prevAddr = (uint64_t)(valuesIP);
449 void checkMovValueNum(
int opcode, uint64_t svalue, uint64_t target, THREADID threadid,
void*
ip,
const uint32_t opHandle) {
453 uint64_t op = (uint64_t)opcode;
454 uint64_t key = (op << 56) | ((svalue & 0x000000000fffffff) << 28) | (target & 0x000000000fffffff);
478 for (
int i = 1; i < count; ++i) {
479 for (
int j = 0; j < i; ++j) {
480 if (svalues[j] > svalues[i]) {
482 svalues[j] = svalues[i];
492 return opcode != XED_ICLASS_SUB && opcode != XED_ICLASS_DIV && opcode != XED_ICLASS_SHL && opcode != XED_ICLASS_SHR;
501 uint64_t op = (uint64_t)opcode;
509 key = (op << 56) | ((svalues[0] << 8) >> 8);
515 key = (op << 56) | ((svalues[0] & 0x000000000fffffff) << 28) | (svalues[1] & 0x000000000fffffff);
521 key = (op << 56) | ((svalues[0] << 45) >> 8) | ((svalues[1] << 45) >> 27) | ((svalues[2] << 45) >> 46);
528 key = (op << 56) | ((svalues[0] & 0x0000000000003fff) << 42) | ((svalues[1] & 0x0000000000003fff) << 28) | ((svalues[2] & 0x0000000000003fff) << 14) | (svalues[3] & 0x0000000000003fff);
531 printf(
"Source values more than 4!\n");
535 key = (op << 56) | ((svalues[0] & 0x000000000fffffff) << 28) | (svalues[1] & 0x000000000fffffff);
564 VOID
valueNumbering(
void* op,
bool movOrnot, THREADID threadid,
void*
ip,
const uint32_t opHandle) {
587 int sRegsCount = opinfo->sCount;
588 int immediateCount = opinfo->immeCount;
593 else if (immediateCount == 1)
594 value = opinfo->immediates[0];
606 for (
int i = 0; i < sRegsCount; ++i)
609 for (
int i = 0; i < immediateCount; ++i)
610 sValues[index++] = opinfo->immediates[i];
615 int tRegsCount = opinfo->tCount;
616 if (tRegsCount == 1) {
619 for (
int i = 0; i < tRegsCount; i++) {
627 VOID
valueNumberingMem1(
void* op,
void* addr, uint32_t rMem, uint32_t wMem,
bool movOrnot, THREADID threadID,
void*
ip,
const uint32_t opHandle) {
648 assert(rMem + wMem == 1);
651 int sRegsCount = opinfo->sCount;
652 int immediateCount = opinfo->immeCount;
656 assert(opinfo->tCount == 1);
672 assert(sRegsCount == 1);
675 else if (immediateCount == 1)
676 value = opinfo->immediates[0];
685 for (
int i = 0; i < sRegsCount; ++i)
688 for (
int i = 0; i < immediateCount; ++i)
689 sValues[index++] = opinfo->immediates[i];
691 int tRegsCount = opinfo->tCount;
695 sValues[index++] =
value;
700 if (tRegsCount == 1) {
703 for (
int i = 0; i < tRegsCount; i++) {
713 if (tRegsCount == 0) {
719 for (
int i = 0; i < tRegsCount; i++) {
728 VOID
valueNumberingMem2(
void* op,
void* addr1,
void* addr2, uint32_t rMem, uint32_t wMem,
bool movOrnot, THREADID threadID,
void*
ip,
const uint32_t opHandle) {
748 assert(rMem + wMem == 2);
751 int sRegsCount = opinfo->sCount;
752 int immediateCount = opinfo->immeCount;
755 if (rMem == 1 && wMem == 1) {
764 for (
int i = 0; i < sRegsCount; ++i)
767 for (
int i = 0; i < immediateCount; ++i)
768 sValues[index++] = opinfo->immediates[i];
770 int tRegsCount = opinfo->tCount;
782 }
else if (rMem == 1) {
785 sValues[index++] =
value;
789 if (tRegsCount == 0) {
795 for (
int i = 0; i < tRegsCount; i++) {
804 sValues[index++] =
value;
807 sValues[index++] =
value;
811 if (tRegsCount == 1) {
814 for (
int i = 0; i < tRegsCount; i++) {
824 VOID
valueNumberingMem3(
void* op,
void* addr1,
void* addr2,
void* addr3, uint32_t rMem, uint32_t wMem,
bool movOrnot, THREADID threadID,
void*
ip,
const uint32_t opHandle) {
844 assert(rMem + wMem == 3);
847 int sRegsCount = opinfo->sCount;
848 int immediateCount = opinfo->immeCount;
856 for (
int i = 0; i < sRegsCount; ++i)
859 for (
int i = 0; i < immediateCount; ++i)
860 sValues[index++] = opinfo->immediates[i];
862 int tRegsCount = opinfo->tCount;
879 for (
int i = 0; i < tRegsCount; i++) {
888 sValues[index++] =
value;
897 for (
int i = 0; i < tRegsCount; i++) {
906 sValues[index++] =
value;
909 sValues[index++] =
value;
913 if (tRegsCount == 0) {
919 for (
int i = 0; i < tRegsCount; i++) {
929 sValues[index++] =
value;
932 sValues[index++] =
value;
935 sValues[index++] =
value;
939 if (tRegsCount == 1) {
942 for (
int i = 0; i < tRegsCount; i++) {
956 VOID
valueNumberingMem4(
void* op,
void* addr1,
void* addr2,
void* addr3,
void* addr4, uint32_t rMem, uint32_t wMem,
bool movOrnot, THREADID threadID,
void*
ip,
const uint32_t opHandle) {
976 assert(rMem + wMem == 4);
979 int sRegsCount = opinfo->sCount;
980 int immediateCount = opinfo->immeCount;
988 for (
int i = 0; i < sRegsCount; ++i)
991 for (
int i = 0; i < immediateCount; ++i)
992 sValues[index++] = opinfo->immediates[i];
994 int tRegsCount = opinfo->tCount;
1013 for (
int i = 0; i < tRegsCount; i++) {
1021 sValues[index++] =
value;
1032 for (
int i = 0; i < tRegsCount; i++) {
1040 sValues[index++] =
value;
1043 sValues[index++] =
value;
1052 for (
int i = 0; i < tRegsCount; i++) {
1060 sValues[index++] =
value;
1063 sValues[index++] =
value;
1066 sValues[index++] =
value;
1070 if (tRegsCount == 0) {
1076 for (
int i = 0; i < tRegsCount; i++) {
1085 sValues[index++] =
value;
1088 sValues[index++] =
value;
1091 sValues[index++] =
value;
1094 sValues[index++] =
value;
1098 if (tRegsCount == 1) {
1101 for (
int i = 0; i < tRegsCount; i++) {
1135 THREADID threadID = PIN_ThreadId();
1137 UINT32 memOpCount = INS_MemoryOperandCount(ins);
1139 UINT32 rMemCount = 0;
1140 UINT32 wMemCount = 0;
1155 for (UINT32 memOp = 0; memOp < memOpCount; memOp++) {
1156 if (INS_IsMemoryRead(ins)) {
1158 rMem.push_back(memOp);
1160 if (INS_IsMemoryWrite(ins)) {
1162 wMem.push_back(memOp);
1166 rMem.insert(rMem.end(), wMem.begin(), wMem.end());
1168 memOpCount = rMemCount + wMemCount;
1171 UINT32 opCode = INS_Opcode(ins);
1176 opinfo->opCode = opCode;
1179 int immediateCount = 0;
1184 if (
IsMov(opinfo->opCode)) {
1185 UINT32 n = INS_OperandCount(ins);
1189 for (UINT32 i = 0; i < n; ++i) {
1190 if (INS_OperandRead(ins, i)) {
1191 if (INS_OperandIsReg(ins, i)) {
1192 REG readReg = INS_OperandReg(ins, i);
1193 opinfo->sRegs[sRegCount++] = readReg;
1195 }
else if (INS_OperandIsImmediate(ins, i)) {
1196 uint64_t immediate = INS_OperandImmediate(ins, i);
1201 if (INS_OperandWritten(ins, i)) {
1202 if (INS_OperandIsReg(ins, i)) {
1203 REG writeReg = INS_OperandReg(ins, i);
1204 opinfo->tRegs[tRegCount++] = writeReg;
1209 UINT32 n = INS_OperandCount(ins);
1216 for (UINT32 i = 0; i < n; ++i) {
1217 if (INS_OperandRead(ins, i)) {
1218 if (INS_OperandIsReg(ins, i)) {
1219 REG readReg = INS_OperandReg(ins, i);
1220 opinfo->sRegs[sRegCount++] = readReg;
1221 }
else if (INS_OperandIsImmediate(ins, i)) {
1222 uint64_t immediate = INS_OperandImmediate(ins, i);
1227 if (INS_OperandWritten(ins, i)) {
1228 if (INS_OperandIsReg(ins, i)) {
1229 REG write = INS_OperandReg(ins, i);
1230 if (write != REG_GFLAGS)
1231 opinfo->tRegs[tRegCount++] = INS_OperandReg(ins, i);
1237 opinfo->sCount = sRegCount;
1238 opinfo->immeCount = immediateCount;
1239 opinfo->tCount = tRegCount;
1242 switch (memOpCount) {
1244 INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)
valueNumbering, IARG_PTR, opinfo, IARG_BOOL, flag, IARG_THREAD_ID, IARG_INST_PTR, IARG_UINT32, opHandle, IARG_END);
1247 INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)
valueNumberingMem1, IARG_PTR, opinfo, IARG_MEMORYOP_EA, rMem[0], IARG_ADDRINT, rMemCount, IARG_ADDRINT, wMemCount, IARG_BOOL, flag, IARG_THREAD_ID, IARG_INST_PTR, IARG_UINT32, opHandle, IARG_END);
1250 INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)
valueNumberingMem2, IARG_PTR, opinfo, IARG_MEMORYOP_EA, rMem[0], IARG_MEMORYOP_EA, rMem[1], IARG_ADDRINT, rMemCount, IARG_ADDRINT, wMemCount, IARG_BOOL, flag, IARG_THREAD_ID, IARG_INST_PTR, IARG_UINT32, opHandle, IARG_END);
1253 INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)
valueNumberingMem3, IARG_PTR, opinfo, IARG_MEMORYOP_EA, rMem[0], IARG_MEMORYOP_EA, rMem[1], IARG_MEMORYOP_EA, rMem[2], IARG_ADDRINT, rMemCount, IARG_ADDRINT, wMemCount, IARG_BOOL, flag, IARG_THREAD_ID, IARG_INST_PTR, IARG_UINT32, opHandle, IARG_END);
1256 INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)
valueNumberingMem4, IARG_PTR, opinfo, IARG_MEMORYOP_EA, rMem[0], IARG_MEMORYOP_EA, rMem[1], IARG_MEMORYOP_EA, rMem[2], IARG_MEMORYOP_EA, rMem[3], IARG_ADDRINT, rMemCount, IARG_ADDRINT, wMemCount, IARG_BOOL, flag, IARG_THREAD_ID, IARG_INST_PTR, IARG_UINT32, opHandle, IARG_END);
1259 assert(memOpCount < 5);
1273 PIN_SetThreadData(
tls_key, tdata, threadid);
1285 return (this->context1 < x.
context1) ||
1300 static void DumpInfo(uint32_t oldIndex, uint32_t newIndex) {
1304 fprintf(
gTraceFile,
"\n *****is redundant because of*****");
1311 fprintf(
gTraceFile,
"\nUnloading %s", IMG_Name(img).c_str());
1316 unordered_map<uint64_t, uint64_t>::iterator mapIt = td->
redundantMap.begin();
1317 map<MergedRedundantInfo, uint64_t> mergedRedundantInfoMap;
1318 map<MergedRedundantInfo, uint64_t>::iterator tmpIt;
1324 uint64_t hash = mapIt->first;
1325 uint32_t ctxt1 = (hash >> 32);
1326 uint32_t ctxt2 = (hash & 0xffffffff);
1327 for (tmpIt = mergedRedundantInfoMap.begin(); tmpIt != mergedRedundantInfoMap.end(); tmpIt++) {
1332 tmpIt->second += mapIt->second;
1336 if (tmpIt == mergedRedundantInfoMap.end()) {
1338 tmpMergedRedundantInfo.
context1 = ctxt1;
1339 tmpMergedRedundantInfo.
context2 = ctxt2;
1340 mergedRedundantInfoMap[tmpMergedRedundantInfo] = mapIt->second;
1345 map<MergedRedundantInfo, uint64_t>::iterator it = mergedRedundantInfoMap.begin();
1347 list<RedundantInfoForPresentation> gRedundantList;
1349 for (; it != mergedRedundantInfoMap.end(); it++) {
1353 redundantInfoForPresentation.
count = it->second;
1354 gRedundantList.push_back(redundantInfoForPresentation);
1365 list<RedundantInfoForPresentation>::iterator dipIter = gRedundantList.begin();
1366 int redundancyWrite = 0;
1367 uint64_t Topredundant = 0;
1368 for (; dipIter != gRedundantList.end(); dipIter++) {
1372 fprintf(
gTraceFile,
"\nCTXT_REDUNDANT_CNT:%lu", dipIter->count);
1373 DumpInfo(dipIter->pMergedRedundantInfo->context1, dipIter->pMergedRedundantInfo->context2);
1374 Topredundant += dipIter->count;
1379 gRedundantList.clear();
1381 PIN_MutexUnlock(&
gMutex);
1389 PIN_ERROR(
"PinTool for runtime value numbering (RVN).\n" + KNOB_BASE::StringKnobSummary() +
"\n");
1398 char* envPath = getenv(
"OUTPUT_FILE");
1401 snprintf(name,
sizeof(name),
"%s", envPath);
1403 gethostname(name + strlen(name),
MAX_FILE_PATH - strlen(name));
1404 pid_t pid = getpid();
1405 sprintf(name + strlen(name),
"%d", pid);
1406 cerr <<
"\n Creating info file at:" << name <<
"\n";
1411 for (
int i = 0; i < argc; i++) {
1417 tls_key = PIN_CreateThreadDataKey(
nullptr);
1441 if (PIN_Init(argc, argv))
#define INTERESTING_INS_ALL
uint64_t regNumber[REG_LAST]
unordered_map< uint64_t, uint64_t >::iterator redundantMapIt
unordered_map< uint64_t, OPMap > opcodeMap
unordered_map< uint64_t, OPMap >::iterator opcodeMapIt
unordered_map< uint64_t, uint64_t >::iterator immediateMapIt
unordered_map< uint64_t, uint64_t > redundantMap
unordered_map< uint64_t, uint64_t > immediateMap
int PinCCTLibInit(IsInterestingInsFptr isInterestingIns, FILE *logFile, CCTLibInstrumentInsCallback userCallback, VOID *userCallbackArg, BOOL doDataCentric=false)
hpcrun_metricFlags_t flags
VOID PrintFullCallingContext(const ContextHandle_t ctxtHandle)
bool IsSameSourceLine(ContextHandle_t ctxt1, ContextHandle_t ctxt2)
ContextHandle_t GetContextHandle(const THREADID id, const uint32_t slot)
static BOOL INS_IsMaskedJump(INS ins)
uint8_t value[MAX_WRITE_OP_LENGTH]
uint64_t checkOpcodeValueNum(int opcode, uint64_t svalues[], int sCount, THREADID threadid, void *ip, const uint32_t opHandle)
void deleteString(uint64_t key, ThreadData_t *td)
static uint8_t ** gL1PageTable[LEVEL_1_PAGE_TABLE_SIZE]
VOID valueNumberingMem4(void *op, void *addr1, void *addr2, void *addr3, void *addr4, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void *ip, const uint32_t opHandle)
int main(int argc, char *argv[])
uint64_t immediates[MAX_OPERAND]
VOID valueNumbering(void *op, bool movOrnot, THREADID threadid, void *ip, const uint32_t opHandle)
uint64_t getRegValueNum(REG reg, THREADID threadid)
#define LEVEL_2_PAGE_TABLE_SIZE
VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v)
#define LEVEL_1_PAGE_TABLE_SLOT(addr)
struct opcodeInfo { OPCODE opCode OPInfo
VOID CleanValueNumbers(THREADID threadID)
VOID Instruction(INS ins, VOID *v, const uint32_t opHandle)
static void DumpInfo(uint32_t oldIndex, uint32_t newIndex)
VOID setRegValueNum(REG reg, ThreadData_t *td, uint64_t value)
#define PAGE_OFFSET(addr)
void recordRedundantOperation(uint32_t deadCtxt, uint32_t killerCtxt, ThreadData_t *td)
VOID valueNumberingMem3(void *op, void *addr1, void *addr2, void *addr3, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void *ip, const uint32_t opHandle)
#define MAX_DEAD_CONTEXTS_TO_LOG
uint64_t getImmediateValueNum(uint64_t immediate, THREADID threadid)
void removeOldstring(void *ip, uint64_t nValue, ThreadData_t *td)
VOID RegDeadFini(INT32 code, VOID *v)
bool IsCommutativeOp(int opcode)
static void sortSvalues(uint64_t *svalues, int count)
VOID setMemValueNum(uint64_t addr, THREADID threadid, uint64_t value)
bool MergedRedundantInfoComparer(const RedundantInfoForPresentation &first, const RedundantInfoForPresentation &second)
VOID valueNumberingMem1(void *op, void *addr, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void *ip, const uint32_t opHandle)
static uint8_t * GetOrCreateShadowBaseAddress(uint64_t address)
uint64_t getMemValueNum(uint64_t addr, THREADID threadid)
VOID ImageUnload(IMG img, VOID *v)
VOID valueNumberingMem2(void *op, void *addr1, void *addr2, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void *ip, const uint32_t opHandle)
ThreadData_t * GetTLS(THREADID threadid)
bool IsIgnorableIns(INS ins)
#define LEVEL_1_PAGE_TABLE_SIZE
struct opMap { uint64_t vNum OPMap
uint64_t Num_instructions
void UpdateValue(uint32_t reg, uint64_t value, ThreadData_t *td)
void InitValueNumbering(int argc, char *argv[])
void checkMovValueNum(int opcode, uint64_t svalue, uint64_t target, THREADID threadid, void *ip, const uint32_t opHandle)
#define LEVEL_2_PAGE_TABLE_SLOT(addr)
bool operator<(const MergedRedundantInfo &x) const
bool operator==(const MergedRedundantInfo &x) const
const MergedRedundantInfo * pMergedRedundantInfo