[LLVMdev] Being able to know the jitted code-size before emitting

Nicolas Geoffray nicolas.geoffray at lip6.fr
Tue Apr 1 00:50:57 PDT 2008


Hi Evan,

Evan Cheng wrote:
> 1) How are you computing size of the method being  
> jitted? 

I add a new pass with addSimpleCodeEmitter, with the emitter being a 
SizeEmitter. Since the target calls the emitter with functions such as 
writeByte, writeWord, etc.... the SizeEmitter class implements these 
function by incrementing a counter.

At the end of the pass, the code size of the function is known.

> 2) Why not simply add the functionality of allocating emission  
> buffer of specific size to MachineCodeEmitter instead?
>   

I don't understand. The MachineCodeEmitter class writes directly to a 
buffer which is remalloc'ed if necessary. I want this buffer to be 
pre-allocated and of the correct size. Hence I need a pass that runs 
before emitting code.

Nicolas
> Thanks,
>
> Evan
>
> On Mar 30, 2008, at 12:05 PM, Nicolas Geoffray wrote:
>
>   
>> Hi everyone,
>>
>> vmkit requires to know the size of a jitted method before emitting  
>> the method. This allows to allocate the correct size for the method.  
>> The attached patch creates this functionality when the flag  
>> SizedMemoryCode is on.
>>
>> In order to implement this functionality, i had to virtualize some  
>> MachineCodeEmitter functions.
>>
>> Is it OK to commit the patch?
>>
>> Thanks,
>> Nicolas
>> Index: include/llvm/Target/TargetOptions.h
>> ===================================================================
>> --- include/llvm/Target/TargetOptions.h (revision 48944)
>> +++ include/llvm/Target/TargetOptions.h (working copy)
>> @@ -74,6 +74,10 @@
>>   /// be emitted.
>>   extern bool ExceptionHandling;
>>
>> +  /// SizedMemoryCode - This flags indicates that memory for code  
>> is allocated by
>> +  /// an external allocator which requires the size to allocate
>> +  extern bool SizedMemoryCode;
>> +
>>   /// PerformTailCallOpt - This flag is enabled when -tailcallopt is  
>> specified
>>   /// on the commandline. When the flag is on, the target will  
>> perform tail call
>>   /// optimization (pop the caller's stack) providing it supports it.
>> Index: include/llvm/CodeGen/SizeEmitter.h
>> ===================================================================
>> --- include/llvm/CodeGen/SizeEmitter.h	(revision 0)
>> +++ include/llvm/CodeGen/SizeEmitter.h	(revision 0)
>> @@ -0,0 +1,116 @@
>> +//===-- llvm/CodeGen/MachineCodeEmitter.h - Code emission -------*-  
>> C++ -*-===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file was developed by the LLVM research group and is  
>> distributed under
>> +// the University of Illinois Open Source License. See LICENSE.TXT  
>> for details.
>> +//
>> +// 
>> = 
>> = 
>> = 
>> ----------------------------------------------------------------------= 
>> ==//
>> +//
>> +// This file defines an abstract interface that is used by the  
>> machine code
>> +// emission framework to output the code.  This allows machine code  
>> emission to
>> +// be separated from concerns such as resolution of call targets,  
>> and where the
>> +// machine code will be written (memory or disk, f.e.).
>> +//
>> +// 
>> = 
>> = 
>> = 
>> ----------------------------------------------------------------------= 
>> ==//
>> +
>> +#ifndef LLVM_CODEGEN_SIZEEMITTER_H
>> +#define LLVM_CODEGEN_SIZEEMITTER_H
>> +
>> +#include "llvm/CodeGen/MachineCodeEmitter.h"
>> +#include "llvm/CodeGen/MachineFunction.h"
>> +
>> +namespace llvm {
>> +  /// SizeEmitter - The JIT implementation of the  
>> MachineCodeEmitter, which is
>> +  /// used to output functions to memory for execution.
>> +class SizeEmitter : public MachineCodeEmitter {
>> +  MachineFunction * Fn;
>> +  void* ConstantPoolBase;
>> +  void* JumpTableBase;
>> +  MachineConstantPool *ConstantPool;
>> +  MachineJumpTableInfo *JumpTable;
>> +  std::vector<intptr_t> LabelLocations;
>> +  MachineCodeEmitter* MCE;
>> +
>> +public:
>> +  SizeEmitter(MachineCodeEmitter* mce) {
>> +    CurBufferPtr = 0;
>> +    BufferBegin = 0;
>> +    BufferEnd = (unsigned char*)-1;
>> +    MCE = mce;
>> +  }
>> +
>> +  SizeEmitter(std::vector<intptr_t> locations) {
>> +    LabelLocations = locations;
>> +    CurBufferPtr = 0;
>> +    BufferBegin = 0;
>> +    BufferEnd = (unsigned char*)-1;
>> +  }
>> +
>> +  void initConstantPool(MachineConstantPool *MCP);
>> +
>> +  void initJumpTableInfo(MachineJumpTableInfo *MJTI);
>> +
>> +
>> +  virtual void startFunction(MachineFunction &F) {
>> +    CurBufferPtr = 0;
>> +    Fn = &F;
>> +
>> +    // Ensure the constant pool/jump table info is at least 4-byte  
>> aligned.
>> +    emitAlignment(16);
>> +
>> +    initConstantPool(F.getConstantPool());
>> +    initJumpTableInfo(F.getJumpTableInfo());
>> +
>> +    ConstantPoolBase  = (void*)(((uintptr_t) ConstantPoolBase) +  
>> CurBufferPtr);
>> +    JumpTableBase     = (void*)(((uintptr_t) JumpTableBase) +  
>> CurBufferPtr);
>> +  }
>> +
>> +  virtual bool finishFunction(MachineFunction &F) {
>> +    MCE->setCurrentPtr(CurBufferPtr);
>> +    return false;
>> +  }
>> +  virtual void startFunctionStub(unsigned StubSize, unsigned  
>> Alignment) {}
>> +  virtual void *finishFunctionStub(const Function *F) { return 0; }
>> +  virtual void addRelocation(const llvm::MachineRelocation&) { }
>> +  virtual void emitByte(unsigned char B) {
>> +    CurBufferPtr++;
>> +  }
>> +  virtual void emitWordLE(unsigned W) {
>> +    CurBufferPtr+=4;
>> +  }
>> +  virtual void emitWordBE(unsigned W) {
>> +    CurBufferPtr+=4;
>> +  }
>> +  virtual void emitInt32(int Value) {
>> +    CurBufferPtr += 4;
>> +  }
>> +  virtual void emitInt64(uint64_t Value) {
>> +    CurBufferPtr += 8;
>> +  }
>> +  virtual void emitAt(uintptr_t *Addr, uintptr_t Value) {
>> +  }
>> +
>> +
>> +
>> +  virtual void StartMachineBasicBlock(MachineBasicBlock *MBB) {}
>> +  virtual intptr_t getConstantPoolEntryAddress(unsigned  
>> ConstantNum) const;
>> +
>> +  virtual intptr_t getJumpTableEntryAddress(unsigned Index) const;
>> +
>> +  virtual intptr_t getMachineBasicBlockAddress(MachineBasicBlock  
>> *MBB) const {
>> +    assert(0 && "Should not be in getMachineBasicBlockAddress of  
>> SizeEmitter");
>> +  }
>> +
>> +  virtual void emitLabel(uint64_t) {}
>> +  virtual intptr_t getLabelAddress(uint64_t LabelID) const {
>> +    assert(LabelLocations.size() > (unsigned)LabelID &&
>> +             LabelLocations[LabelID] && "Label not emitted!");
>> +      return LabelLocations[LabelID];
>> +  }
>> +  virtual void setModuleInfo(llvm::MachineModuleInfo*) {}
>> +};
>> +
>> +} // end llvm namespace
>> +
>> +#endif
>> Index: include/llvm/CodeGen/MachineCodeEmitter.h
>> ===================================================================
>> --- include/llvm/CodeGen/MachineCodeEmitter.h	(revision 48143)
>> +++ include/llvm/CodeGen/MachineCodeEmitter.h	(working copy)
>> @@ -18,6 +18,7 @@
>> #define LLVM_CODEGEN_MACHINECODEEMITTER_H
>>
>> #include "llvm/Support/DataTypes.h"
>> +#include <string>
>> #include <vector>
>>
>> namespace llvm {
>> @@ -92,7 +93,7 @@
>>   /// emitByte - This callback is invoked when a byte needs to be  
>> written to the
>>   /// output stream.
>>   ///
>> -  void emitByte(unsigned char B) {
>> +  virtual void emitByte(unsigned char B) {
>>     if (CurBufferPtr != BufferEnd)
>>       *CurBufferPtr++ = B;
>>   }
>> @@ -100,7 +101,7 @@
>>   /// emitWordLE - This callback is invoked when a 32-bit word needs  
>> to be
>>   /// written to the output stream in little-endian format.
>>   ///
>> -  void emitWordLE(unsigned W) {
>> +  virtual void emitWordLE(unsigned W) {
>>     if (CurBufferPtr+4 <= BufferEnd) {
>>       *CurBufferPtr++ = (unsigned char)(W >>  0);
>>       *CurBufferPtr++ = (unsigned char)(W >>  8);
>> @@ -114,7 +115,7 @@
>>   /// emitWordBE - This callback is invoked when a 32-bit word needs  
>> to be
>>   /// written to the output stream in big-endian format.
>>   ///
>> -  void emitWordBE(unsigned W) {
>> +  virtual void emitWordBE(unsigned W) {
>>     if (CurBufferPtr+4 <= BufferEnd) {
>>       *CurBufferPtr++ = (unsigned char)(W >> 24);
>>       *CurBufferPtr++ = (unsigned char)(W >> 16);
>> @@ -175,7 +176,7 @@
>>   }
>>
>>   /// emitInt32 - Emit a int32 directive.
>> -  void emitInt32(int Value) {
>> +  virtual void emitInt32(int Value) {
>>     if (CurBufferPtr+4 <= BufferEnd) {
>>       *((uint32_t*)CurBufferPtr) = Value;
>>       CurBufferPtr += 4;
>> @@ -185,7 +186,7 @@
>>   }
>>
>>   /// emitInt64 - Emit a int64 directive.
>> -  void emitInt64(uint64_t Value) {
>> +  virtual void emitInt64(uint64_t Value) {
>>     if (CurBufferPtr+8 <= BufferEnd) {
>>       *((uint64_t*)CurBufferPtr) = Value;
>>       CurBufferPtr += 8;
>> @@ -195,7 +196,7 @@
>>   }
>>
>>   /// emitAt - Emit Value in Addr
>> -  void emitAt(uintptr_t *Addr, uintptr_t Value) {
>> +  virtual void emitAt(uintptr_t *Addr, uintptr_t Value) {
>>     if (Addr >= (uintptr_t*)BufferBegin && Addr <  
>> (uintptr_t*)BufferEnd)
>>       (*Addr) = Value;
>>   }
>> @@ -270,6 +271,11 @@
>>   /// Specifies the MachineModuleInfo object. This is used for  
>> exception handling
>>   /// purposes.
>>   virtual void setModuleInfo(MachineModuleInfo* Info) = 0;
>> +
>> +  void setCurrentPtr(unsigned char* Ptr) {
>> +    CurBufferPtr = Ptr;
>> +  }
>> +
>> };
>>
>> } // End llvm namespace
>> Index: lib/CodeGen/LLVMTargetMachine.cpp
>> ===================================================================
>> --- lib/CodeGen/LLVMTargetMachine.cpp	(revision 48143)
>> +++ lib/CodeGen/LLVMTargetMachine.cpp	(working copy)
>> @@ -17,6 +17,7 @@
>> #include "llvm/Assembly/PrintModulePass.h"
>> #include "llvm/Analysis/LoopPass.h"
>> #include "llvm/CodeGen/Passes.h"
>> +#include "llvm/CodeGen/SizeEmitter.h"
>> #include "llvm/CodeGen/Collector.h"
>> #include "llvm/Target/TargetOptions.h"
>> #include "llvm/Transforms/Scalar.h"
>> @@ -257,7 +258,13 @@
>>
>>   if (addPreEmitPass(PM, Fast) && PrintMachineCode)
>>     PM.add(createMachineFunctionPrinterPass(cerr));
>> +
>> +  if (SizedMemoryCode) {
>> +    SizeEmitter * SE = new SizeEmitter(&MCE);
>> +    addSimpleCodeEmitter(PM, Fast, false, *SE);
>> +  }
>>
>> +
>>   addCodeEmitter(PM, Fast, PrintEmittedAsm, MCE);
>>
>>   PM.add(createCollectorMetadataDeleter());
>> Index: lib/CodeGen/SizeEmitter.cpp
>> ===================================================================
>> --- lib/CodeGen/SizeEmitter.cpp	(revision 0)
>> +++ lib/CodeGen/SizeEmitter.cpp	(revision 0)
>> @@ -0,0 +1,77 @@
>> +#include "llvm/CodeGen/SizeEmitter.h"
>> +#include "llvm/Constant.h"
>> +#include "llvm/Constants.h"
>> +#include "llvm/DerivedTypes.h"
>> +#include "llvm/Module.h"
>> +#include "llvm/Type.h"
>> +#include "llvm/CodeGen/MachineCodeEmitter.h"
>> +#include "llvm/CodeGen/MachineFunction.h"
>> +#include "llvm/CodeGen/MachineConstantPool.h"
>> +#include "llvm/CodeGen/MachineJumpTableInfo.h"
>> +#include "llvm/CodeGen/MachineRelocation.h"
>> +#include "llvm/ExecutionEngine/GenericValue.h"
>> +#include "llvm/Target/TargetData.h"
>> +#include "llvm/Target/TargetJITInfo.h"
>> +#include "llvm/Target/TargetMachine.h"
>> +#include "llvm/Target/TargetOptions.h"
>> +#include "llvm/Support/Debug.h"
>> +#include "llvm/Support/MutexGuard.h"
>> +#include "llvm/System/Disassembler.h"
>> +#include "llvm/ADT/Statistic.h"
>> +#include "llvm/System/Memory.h"
>> +#include <algorithm>
>> +using namespace llvm;
>> +
>> +
>> +void SizeEmitter::initConstantPool(MachineConstantPool *MCP) {
>> +  const std::vector<MachineConstantPoolEntry> &Constants = MCP- 
>>     
>>> getConstants();
>>>       
>> +  if (Constants.empty()) return;
>> +
>> +  MachineConstantPoolEntry CPE = Constants.back();
>> +  unsigned Size = CPE.Offset;
>> +  const Type *Ty = CPE.isMachineConstantPoolEntry()
>> +    ? CPE.Val.MachineCPVal->getType() : CPE.Val.ConstVal->getType();
>> +  Size += Fn->getTarget().getTargetData()->getABITypeSize(Ty);
>> +  ConstantPoolBase = allocateSpace(Size, 1 << MCP- 
>>     
>>> getConstantPoolAlignment());
>>>       
>> +  ConstantPool = MCP;
>> +}
>> +
>> +void SizeEmitter::initJumpTableInfo(MachineJumpTableInfo *MJTI) {
>> +  const std::vector<MachineJumpTableEntry> &JT = MJTI- 
>>     
>>> getJumpTables();
>>>       
>> +  if (JT.empty()) return;
>> +
>> +  unsigned NumEntries = 0;
>> +  for (unsigned i = 0, e = JT.size(); i != e; ++i)
>> +    NumEntries += JT[i].MBBs.size();
>> +
>> +  unsigned EntrySize = MJTI->getEntrySize();
>> +
>> +  // Just allocate space for all the jump tables now.  We will fix  
>> up the actual
>> +  // MBB entries in the tables after we emit the code for each  
>> block, since then
>> +  // we will know the final locations of the MBBs in memory.
>> +  JumpTable = MJTI;
>> +  JumpTableBase = allocateSpace(NumEntries * EntrySize, MJTI- 
>>     
>>> getAlignment());
>>>       
>> +}
>> +
>> +intptr_t SizeEmitter::getConstantPoolEntryAddress(unsigned  
>> ConstantNum) const {
>> +  assert(ConstantNum < ConstantPool->getConstants().size() &&
>> +         "Invalid ConstantPoolIndex!");
>> +  return (intptr_t)ConstantPoolBase +
>> +         ConstantPool->getConstants()[ConstantNum].Offset;
>> +}
>> +
>> +intptr_t SizeEmitter::getJumpTableEntryAddress(unsigned Index)  
>> const {
>> +  const std::vector<MachineJumpTableEntry> &JT = JumpTable- 
>>     
>>> getJumpTables();
>>>       
>> +  assert(Index < JT.size() && "Invalid jump table index!");
>> +
>> +  unsigned Offset = 0;
>> +  unsigned EntrySize = JumpTable->getEntrySize();
>> +
>> +  for (unsigned i = 0; i < Index; ++i)
>> +    Offset += JT[i].MBBs.size();
>> +
>> +   Offset *= EntrySize;
>> +
>> +  return (intptr_t)((char *)JumpTableBase + Offset);
>> +}
>> +
>> Index: lib/Target/TargetMachine.cpp
>> ===================================================================
>> --- lib/Target/TargetMachine.cpp	(revision 48143)
>> +++ lib/Target/TargetMachine.cpp	(working copy)
>> @@ -31,6 +31,7 @@
>>   bool UseSoftFloat;
>>   bool NoZerosInBSS;
>>   bool ExceptionHandling;
>> +  bool SizedMemoryCode;
>>   Reloc::Model RelocationModel;
>>   CodeModel::Model CMModel;
>>   bool PerformTailCallOpt;
>> Index: lib/ExecutionEngine/JIT/JITEmitter.cpp
>> ===================================================================
>> --- lib/ExecutionEngine/JIT/JITEmitter.cpp	(revision 48143)
>> +++ lib/ExecutionEngine/JIT/JITEmitter.cpp	(working copy)
>> @@ -18,12 +18,14 @@
>> #include "llvm/Constant.h"
>> #include "llvm/Module.h"
>> #include "llvm/Type.h"
>> +#include "llvm/ADT/DenseMap.h"
>> #include "llvm/CodeGen/MachineCodeEmitter.h"
>> #include "llvm/CodeGen/MachineFunction.h"
>> #include "llvm/CodeGen/MachineConstantPool.h"
>> #include "llvm/CodeGen/MachineJumpTableInfo.h"
>> #include "llvm/CodeGen/MachineModuleInfo.h"
>> #include "llvm/CodeGen/MachineRelocation.h"
>> +#include "llvm/CodeGen/SizeEmitter.h"
>> #include "llvm/ExecutionEngine/JITMemoryManager.h"
>> #include "llvm/Target/TargetData.h"
>> #include "llvm/Target/TargetJITInfo.h"
>> @@ -370,6 +376,7 @@
>>     virtual void startFunction(MachineFunction &F);
>>     virtual bool finishFunction(MachineFunction &F);
>>
>> +    void initConstantPool(MachineConstantPool *MCP);
>>     void emitConstantPool(MachineConstantPool *MCP);
>>     void initJumpTableInfo(MachineJumpTableInfo *MJTI);
>>     void emitJumpTableInfo(MachineJumpTableInfo *MJTI);
>> @@ -469,19 +476,47 @@
>>
>>
>> void JITEmitter::startFunction(MachineFunction &F) {
>> -  uintptr_t ActualSize;
>> -  BufferBegin = CurBufferPtr = MemMgr- 
>>     
>>> startFunctionBody(F.getFunction(),
>>>       
>> -                                                         ActualSize);
>> -  BufferEnd = BufferBegin+ActualSize;
>> +  MMI->BeginFunction(&F);
>>
>> -  // Ensure the constant pool/jump table info is at least 4-byte  
>> aligned.
>> -  emitAlignment(16);
>> +  if (SizedMemoryCode) {
>> +    BufferBegin = CurBufferPtr;
>> +    BufferEnd = (unsigned char*) 0xffffffff;
>> +
>> +    // Ensure the constant pool/jump table info is at least 4-byte  
>> aligned.
>> +    emitAlignment(16);
>>
>> -  emitConstantPool(F.getConstantPool());
>> -  initJumpTableInfo(F.getJumpTableInfo());
>> +    initConstantPool(F.getConstantPool());
>> +    initJumpTableInfo(F.getJumpTableInfo());
>> +
>> +
>> +    uintptr_t ActualSize = (uintptr_t)CurBufferPtr;
>> +    CurBufferPtr = MemMgr->startFunctionBody(F.getFunction(),
>> +                                             ActualSize);
>> +
>> +    ConstantPoolBase  = (void*)(((unsigned) ConstantPoolBase) +  
>> CurBufferPtr);
>> +    JumpTableBase     = (void*)(((unsigned) JumpTableBase) +  
>> CurBufferPtr);
>>
>> -  // About to start emitting the machine code for the function.
>> -  emitAlignment(std::max(F.getFunction()->getAlignment(), 8U));
>> +    emitConstantPool(F.getConstantPool());
>> +
>> +  } else {
>> +    uintptr_t ActualSize;
>> +    BufferBegin = CurBufferPtr = MemMgr- 
>>     
>>> startFunctionBody(F.getFunction(),
>>>       
>> +                                                            
>> ActualSize);
>> +    BufferEnd = BufferBegin+ActualSize;
>> +
>> +    // Ensure the constant pool/jump table info is at least 4-byte  
>> aligned.
>> +    emitAlignment(16);
>> +
>> +    initConstantPool(F.getConstantPool());
>> +    emitConstantPool(F.getConstantPool());
>> +    initJumpTableInfo(F.getJumpTableInfo());
>> +
>> +    // About to start emitting the machine code for the function.
>> +    emitAlignment(std::max(F.getFunction()->getAlignment(), 8U));
>> +
>> +  }
>> +
>> +
>>   TheJIT->updateGlobalMapping(F.getFunction(), CurBufferPtr);
>>
>>   MBBLocations.clear();
>> @@ -579,12 +614,18 @@
>>     DOUT << "Disassembled code:\n"
>>          << sys::disassembleBuffer(FnStart, FnEnd-FnStart,  
>> (uintptr_t)FnStart);
>> #endif
>> +
>>   if (ExceptionHandling) {
>>     uintptr_t ActualSize;
>> +    if (SizedMemoryCode) {
>> +      SizeEmitter sz(LabelLocations);
>> +      DE->EmitDwarfTable(F, sz, FnStart, FnEnd);
>> +      ActualSize = sz.getCurrentPCValue();
>> +    }
>>     SavedBufferBegin = BufferBegin;
>>     SavedBufferEnd = BufferEnd;
>>     SavedCurBufferPtr = CurBufferPtr;
>> -
>> +
>>     BufferBegin = CurBufferPtr = MemMgr- 
>>     
>>> startExceptionTable(F.getFunction(),
>>>       
>>                                                               
>> ActualSize);
>>     BufferEnd = BufferBegin+ActualSize;
>> @@ -598,11 +639,10 @@
>>     TheJIT->RegisterTable(FrameRegister);
>>   }
>>   MMI->EndFunction();
>> -
>>   return false;
>> }
>>
>> -void JITEmitter::emitConstantPool(MachineConstantPool *MCP) {
>> +void JITEmitter::initConstantPool(MachineConstantPool *MCP) {
>>   const std::vector<MachineConstantPoolEntry> &Constants = MCP- 
>>     
>>> getConstants();
>>>       
>>   if (Constants.empty()) return;
>>
>> @@ -611,12 +651,15 @@
>>   const Type *Ty = CPE.isMachineConstantPoolEntry()
>>     ? CPE.Val.MachineCPVal->getType() : CPE.Val.ConstVal->getType();
>>   Size += TheJIT->getTargetData()->getABITypeSize(Ty);
>> -
>> +
>>   ConstantPoolBase = allocateSpace(Size, 1 << MCP- 
>>     
>>> getConstantPoolAlignment());
>>>       
>>   ConstantPool = MCP;
>> +}
>>
>> +void JITEmitter::emitConstantPool(MachineConstantPool *MCP) {
>>   if (ConstantPoolBase == 0) return;  // Buffer overflow.
>>
>> +  const std::vector<MachineConstantPoolEntry> &Constants = MCP- 
>>     
>>> getConstants();
>>>       
>>   // Initialize the memory for all of the constant pool entries.
>>   for (unsigned i = 0, e = Constants.size(); i != e; ++i) {
>>     void *CAddr = (char*)ConstantPoolBase+Constants[i].Offset;
>> _______________________________________________
>> LLVM Developers mailing list
>> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>>     
>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>   




More information about the llvm-dev mailing list