InterferenceCache.h revision f1c709837bd11c5383fce3b8a026a7c8eaabba86
15907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen//===-- InterferenceCache.h - Caching per-block interference ---*- C++ -*--===// 25907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen// 35907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen// The LLVM Compiler Infrastructure 45907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen// 55907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen// This file is distributed under the University of Illinois Open Source 65907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen// License. See LICENSE.TXT for details. 75907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen// 85907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen//===----------------------------------------------------------------------===// 95907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen// 105907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen// InterferenceCache remembers per-block interference in LiveIntervalUnions. 115907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen// 125907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen//===----------------------------------------------------------------------===// 135907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 145907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen#ifndef LLVM_CODEGEN_INTERFERENCECACHE 155907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen#define LLVM_CODEGEN_INTERFERENCECACHE 165907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 175907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen#include "LiveIntervalUnion.h" 185907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 195907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesennamespace llvm { 205907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 215907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesenclass InterferenceCache { 225907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen const TargetRegisterInfo *TRI; 235907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen LiveIntervalUnion *LIUArray; 245907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen SlotIndexes *Indexes; 255907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen MachineFunction *MF; 265907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 275907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// BlockInterference - information about the interference in a single basic 285907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// block. 295907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen struct BlockInterference { 305907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen BlockInterference() : Tag(0) {} 315907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen unsigned Tag; 325907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen SlotIndex First; 335907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen SlotIndex Last; 345907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen }; 355907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 365907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// Entry - A cache entry containing interference information for all aliases 375907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// of PhysReg in all basic blocks. 385907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen class Entry { 395907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// PhysReg - The register currently represented. 405907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen unsigned PhysReg; 415907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 425907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// Tag - Cache tag is changed when any of the underlying LiveIntervalUnions 435907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// change. 445907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen unsigned Tag; 455907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 46f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen /// RefCount - The total number of Cursor instances referring to this Entry. 47f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen unsigned RefCount; 48f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen 499d29cbad32814f31c91cd2464a3c74df412b0aacJakob Stoklund Olesen /// MF - The current function. 509d29cbad32814f31c91cd2464a3c74df412b0aacJakob Stoklund Olesen MachineFunction *MF; 519d29cbad32814f31c91cd2464a3c74df412b0aacJakob Stoklund Olesen 525907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// Indexes - Mapping block numbers to SlotIndex ranges. 535907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen SlotIndexes *Indexes; 545907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 555907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// PrevPos - The previous position the iterators were moved to. 565907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen SlotIndex PrevPos; 575907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 585907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// AliasTags - A LiveIntervalUnion pointer and tag for each alias of 595907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// PhysReg. 605907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen SmallVector<std::pair<LiveIntervalUnion*, unsigned>, 8> Aliases; 615907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 625907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen typedef LiveIntervalUnion::SegmentIter Iter; 635907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 645907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// Iters - an iterator for each alias 655907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen SmallVector<Iter, 8> Iters; 665907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 675907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// Blocks - Interference for each block in the function. 685907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen SmallVector<BlockInterference, 8> Blocks; 695907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 705907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// update - Recompute Blocks[MBBNum] 715907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen void update(unsigned MBBNum); 725907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 735907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen public: 74f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen Entry() : PhysReg(0), Tag(0), RefCount(0), Indexes(0) {} 755907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 769d29cbad32814f31c91cd2464a3c74df412b0aacJakob Stoklund Olesen void clear(MachineFunction *mf, SlotIndexes *indexes) { 77f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen assert(!hasRefs() && "Cannot clear cache entry with references"); 785907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen PhysReg = 0; 799d29cbad32814f31c91cd2464a3c74df412b0aacJakob Stoklund Olesen MF = mf; 805907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen Indexes = indexes; 815907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen } 825907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 835907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen unsigned getPhysReg() const { return PhysReg; } 845907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 85f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen void addRef(int Delta) { RefCount += Delta; } 86f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen 87f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen bool hasRefs() const { return RefCount > 0; } 88f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen 895907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen void revalidate(); 905907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 915907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// valid - Return true if this is a valid entry for physReg. 925907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen bool valid(LiveIntervalUnion *LIUArray, const TargetRegisterInfo *TRI); 935907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 945907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// reset - Initialize entry to represent physReg's aliases. 955907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen void reset(unsigned physReg, 965907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen LiveIntervalUnion *LIUArray, 975907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen const TargetRegisterInfo *TRI, 985907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen const MachineFunction *MF); 995907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1005907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// get - Return an up to date BlockInterference. 1015907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen BlockInterference *get(unsigned MBBNum) { 1025907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen if (Blocks[MBBNum].Tag != Tag) 1035907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen update(MBBNum); 1045907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen return &Blocks[MBBNum]; 1055907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen } 1065907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen }; 1075907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1085907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen // We don't keep a cache entry for every physical register, that would use too 1095907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen // much memory. Instead, a fixed number of cache entries are used in a round- 1105907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen // robin manner. 1115907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen enum { CacheEntries = 32 }; 1125907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1135907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen // Point to an entry for each physreg. The entry pointed to may not be up to 1145907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen // date, and it may have been reused for a different physreg. 1155907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen SmallVector<unsigned char, 2> PhysRegEntries; 1165907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1175907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen // Next round-robin entry to be picked. 1185907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen unsigned RoundRobin; 1195907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1205907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen // The actual cache entries. 1215907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen Entry Entries[CacheEntries]; 1225907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1235907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen // get - Get a valid entry for PhysReg. 1245907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen Entry *get(unsigned PhysReg); 1255907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1265907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesenpublic: 1275907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen InterferenceCache() : TRI(0), LIUArray(0), Indexes(0), MF(0), RoundRobin(0) {} 1285907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1295907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// init - Prepare cache for a new function. 1305907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen void init(MachineFunction*, LiveIntervalUnion*, SlotIndexes*, 1315907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen const TargetRegisterInfo *); 1325907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 133f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen /// getMaxCursors - Return the maximum number of concurrent cursors that can 134f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen /// be supported. 135f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen unsigned getMaxCursors() const { return CacheEntries; } 136f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen 1375907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// Cursor - The primary query interface for the block interference cache. 1385907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen class Cursor { 1395907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen Entry *CacheEntry; 1405907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen BlockInterference *Current; 141f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen 142f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen void setEntry(Entry *E) { 143f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen Current = 0; 144f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen // Update reference counts. Nothing happens when RefCount reaches 0, so 145f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen // we don't have to check for E == CacheEntry etc. 146f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen if (CacheEntry) 147f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen CacheEntry->addRef(-1); 148f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen CacheEntry = E; 149f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen if (CacheEntry) 150f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen CacheEntry->addRef(+1); 151f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen } 152f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen 1535907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen public: 154c66a37df73f70ec3dbed06277763624f33ee3512Jakob Stoklund Olesen /// Cursor - Create a dangling cursor. 155c66a37df73f70ec3dbed06277763624f33ee3512Jakob Stoklund Olesen Cursor() : CacheEntry(0), Current(0) {} 156f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen ~Cursor() { setEntry(0); } 157f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen 158f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen Cursor(const Cursor &O) : CacheEntry(0), Current(0) { 159f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen setEntry(O.CacheEntry); 160f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen } 161f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen 162f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen Cursor &operator=(const Cursor &O) { 163f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen setEntry(O.CacheEntry); 164f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen return *this; 165f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen } 166c66a37df73f70ec3dbed06277763624f33ee3512Jakob Stoklund Olesen 167c66a37df73f70ec3dbed06277763624f33ee3512Jakob Stoklund Olesen /// setPhysReg - Point this cursor to PhysReg's interference. 168c66a37df73f70ec3dbed06277763624f33ee3512Jakob Stoklund Olesen void setPhysReg(InterferenceCache &Cache, unsigned PhysReg) { 169f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen // Release reference before getting a new one. That guarantees we can 170f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen // actually have CacheEntries live cursors. 171f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen setEntry(0); 172f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen if (PhysReg) 173f1c709837bd11c5383fce3b8a026a7c8eaabba86Jakob Stoklund Olesen setEntry(Cache.get(PhysReg)); 174c66a37df73f70ec3dbed06277763624f33ee3512Jakob Stoklund Olesen } 1755907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1765907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// moveTo - Move cursor to basic block MBBNum. 1775907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen void moveToBlock(unsigned MBBNum) { 1785907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen Current = CacheEntry->get(MBBNum); 1795907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen } 1805907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1815907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// hasInterference - Return true if the current block has any interference. 1825907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen bool hasInterference() { 1835907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen return Current->First.isValid(); 1845907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen } 1855907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1865907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// first - Return the starting index of the first interfering range in the 1875907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// current block. 1885907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen SlotIndex first() { 1895907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen return Current->First; 1905907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen } 1915907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1925907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// last - Return the ending index of the last interfering range in the 1935907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen /// current block. 1945907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen SlotIndex last() { 1955907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen return Current->Last; 1965907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen } 1975907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen }; 1985907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 1995907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen friend class Cursor; 2005907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen}; 2015907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 2025907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen} // namespace llvm 2035907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen 2045907d863659eb972ebb2afe07bc863a4c616f0efJakob Stoklund Olesen#endif 205