Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / liveness.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 // $Id: liveness.C,v 1.12 2008/09/04 21:06:20 bill Exp $
33
34 #if defined(cap_liveness)
35
36 #include "debug.h"
37 #include "image-func.h"
38 #include "function.h"
39 #include "instPoint.h"
40 #include "registerSpace.h"
41 #include "debug.h"
42 #if defined(cap_instruction_api)
43 #include "instructionAPI/h/InstructionDecoder.h"
44 #include "instructionAPI/h/Register.h"
45 #include "instructionAPI/h/Instruction.h"
46 #include "addressSpace.h"
47 using namespace Dyninst::InstructionAPI;
48 #else
49 #include "InstrucIter.h"
50 #endif // defined(cap_instruction_api)
51 #include "symtab.h"
52
53 #if defined(arch_x86) || defined(arch_x86_64)
54 // Special-casing for IA-32...
55 #include "RegisterConversion-x86.h"
56 #include "inst-x86.h"
57 #endif
58
59 #if defined(cap_instruction_api)
60 ReadWriteInfo calcRWSets(Instruction::Ptr insn, image_basicBlock* blk, unsigned width);
61 #else
62 ReadWriteInfo calcRWSets(InstrucIter ii, image_basicBlock* blk, unsigned width);
63 #endif
64 InstructionCache image_basicBlock::cachedLivenessInfo = InstructionCache();
65
66   
67
68
69 // Code for register liveness detection
70
71 // Takes information from instPoint and resets
72 // regSpace liveness information accordingly
73 // Right now, all the registers are assumed to be live by default
74 void registerSpace::specializeSpace(const bitArray &liveRegs) {
75     // Liveness info is stored as a single bitarray for all registers.
76
77 #if defined(arch_x86) || defined(arch_x86_64) 
78     // We use "virtual" registers on the IA-32 platform (or AMD-64 in 
79     // 32-bit mode), and thus the registerSlot objects have _no_ relation
80     // to the liveRegs input set. We handle this as a special case, and
81     // look only for the flags representation (which is used to set
82     // the IA32_FLAG_VIRTUAL_REGISTER "register"
83     assert(liveRegs.size() == getBitArray().size());
84     if (addr_width == 4) {
85         for (unsigned i = 1; i <= NUM_VIRTUAL_REGISTERS; i++) {
86             registers_[i]->liveState = registerSlot::dead;
87         }
88         registers_[IA32_FLAG_VIRTUAL_REGISTER]->liveState = registerSlot::dead;
89         for (unsigned i = REGNUM_OF; i <= REGNUM_RF; i++) {
90             if (liveRegs[i]) {
91                 registers_[IA32_FLAG_VIRTUAL_REGISTER]->liveState = registerSlot::live;
92                 break;
93             }
94         }
95         // All we care about for now.
96         return;
97     }
98 #endif
99     assert(liveRegs.size() == getBitArray().size());
100     for (regDictIter i = registers_.begin(); i != registers_.end(); i++) {
101         if (liveRegs[i.currval()->number])
102             i.currval()->liveState = registerSlot::live;
103         else
104             i.currval()->liveState = registerSlot::dead;
105     }
106 #if defined(arch_x86_64)
107     // ???
108     registers_[REGNUM_RAX]->liveState = registerSlot::live;
109 #endif
110
111 }
112
113 const bitArray &image_basicBlock::getLivenessIn() {
114     // Calculate if it hasn't been done already
115     if (in.size() == 0)
116         summarizeBlockLivenessInfo();
117     return in;
118 }
119
120 const bitArray image_basicBlock::getLivenessOut() const {
121     bitArray out(in.size());
122
123     // OUT(X) = UNION(IN(Y)) for all successors Y of X
124     pdvector<image_edge *> target_edges;
125     getTargets(target_edges);
126     
127     for(unsigned i = 0; i < target_edges.size(); i++) {
128         if (target_edges[i]->getType() == ET_CALL) continue;
129         // Is this correct?
130         if (target_edges[i]->getType() == ET_CATCH) continue;
131         
132         // TODO: multiple entry functions and you?
133         
134         if (target_edges[i]->getTarget()) {
135             out |= target_edges[i]->getTarget()->getLivenessIn();
136         }
137     }
138     return out;
139 }
140
141 void image_basicBlock::summarizeBlockLivenessInfo() 
142 {
143    if(in.size())
144    {
145       return;
146    }
147
148    stats_codegen.startTimer(CODEGEN_LIVENESS_TIMER);
149
150    unsigned width = getFirstFunc()->img()->getObject()->getAddressWidth();
151
152    in = registerSpace::getBitArray();
153    def = in;
154    use = in;
155
156    liveness_printf("%s[%d]: Getting liveness summary for block starting at 0x%lx\n",
157                    FILE__, __LINE__, firstInsnOffset());
158
159
160 #if defined(cap_instruction_api)
161    using namespace Dyninst::InstructionAPI;
162    Address current = firstInsnOffset();
163    InstructionDecoder decoder(reinterpret_cast<const unsigned char*>(getPtrToInstruction(firstInsnOffset())), 
164                               getSize());
165    decoder.setMode(getFirstFunc()->img()->getAddressWidth() == 8);
166    Instruction::Ptr curInsn = decoder.decode();
167    while(curInsn && curInsn->isValid())
168    {
169      ReadWriteInfo curInsnRW;
170      if(!cachedLivenessInfo.getLivenessInfo(current, getFirstFunc(), curInsnRW))
171      {
172        curInsnRW = calcRWSets(curInsn, this, width);
173        cachedLivenessInfo.insertInstructionInfo(current, curInsnRW, getFirstFunc());
174      }
175      use |= (curInsnRW.read & ~def);
176      // And if written, then was defined
177      def |= curInsnRW.written;
178       
179 /*     liveness_printf("%s[%d] After instruction %s at address 0x%lx:\n",
180                      FILE__, __LINE__, curInsn->format().c_str(), current);
181      liveness_cerr << "        " << "?XXXXXXXXMMMMMMMMRNDITCPAZSOF11111100DSBSBDCA" << endl;
182      liveness_cerr << "        " << "?7654321076543210FTFFFFFFFFFP54321098IIPPXXXX" << endl;
183      liveness_cerr << "Read    " << curInsnRW.read << endl;
184      liveness_cerr << "Written " << curInsnRW.written << endl;
185      liveness_cerr << "Used    " << use << endl;
186      liveness_cerr << "Defined " << def << endl;*/
187
188       current += curInsn->size();
189       curInsn = decoder.decode();
190    }
191 #else    
192    InstrucIter ii(this);
193    while(ii.hasMore()) {
194      ReadWriteInfo curInsnRW;
195      if(!cachedLivenessInfo.getLivenessInfo(*ii, getFirstFunc(), curInsnRW))
196      {
197        curInsnRW = calcRWSets(ii, this, width);
198        cachedLivenessInfo.insertInstructionInfo(*ii, curInsnRW, getFirstFunc());
199      }
200       // If something is read, then it has been used.
201       use |= (curInsnRW.read & ~def);
202       // And if written, then was defined
203       def |= curInsnRW.written;
204
205         //liveness_printf("%s[%d] After instruction at address 0x%lx:\n", FILE__, __LINE__, *ii);
206         //liveness_cerr << curInsnRW.read << endl << curInsnRW.written << endl << use << endl << def << endl;
207         
208       ++ii;
209    }
210 #endif // (cap_instruction_api)
211      //liveness_printf("%s[%d] Liveness summary for block:\n", FILE__, __LINE__);
212      //liveness_cerr << in << endl << def << endl << use << endl;
213      //liveness_printf("%s[%d] --------------------\n---------------------\n", FILE__, __LINE__);
214
215    stats_codegen.stopTimer(CODEGEN_LIVENESS_TIMER);
216    return;
217 }
218
219 /* This is used to do fixed point iteration until 
220    the in and out don't change anymore */
221 bool image_basicBlock::updateBlockLivenessInfo() 
222 {
223   bool change = false;
224
225   stats_codegen.startTimer(CODEGEN_LIVENESS_TIMER);
226
227   // old_IN = IN(X)
228   bitArray oldIn = in;
229   // tmp is an accumulator
230   bitArray out = getLivenessOut();
231   
232   // Liveness is a reverse dataflow algorithm
233  
234   // OUT(X) = UNION(IN(Y)) for all successors Y of X
235
236   // IN(X) = USE(X) + (OUT(X) - DEF(X))
237   in = use | (out - def);
238   
239   // if (old_IN != IN(X)) then change = true
240   if (in != oldIn)
241       change = true;
242       
243   //liveness_printf("%s[%d] Step: block 0x%lx, hasChanged %d\n", FILE__, __LINE__, firstInsnOffset(), change);
244   //liveness_cerr << in << endl;
245
246   stats_codegen.stopTimer(CODEGEN_LIVENESS_TIMER);
247
248   return change;
249 }
250
251 // Calculate basic block summaries of liveness information
252 // TODO: move this to an image_func level. 
253
254 void image_func::calcBlockLevelLiveness() {
255     if (livenessCalculated_) return;
256
257     // Make sure we have parsed...
258     blocks();
259
260     // Step 1: gather the block summaries
261     set<image_basicBlock*,image_basicBlock::compare>::iterator sit;
262     for(sit = blockList.begin(); sit != blockList.end(); sit++) {
263         (*sit)->summarizeBlockLivenessInfo();
264     }
265     
266     // We now have block-level summaries of gen/kill info
267     // within the block. Propagate this via standard fixpoint
268     // calculation
269     bool changed = true;
270     while (changed) {
271         changed = false;
272         for(sit = blockList.begin(); sit != blockList.end(); sit++) {
273             if ((*sit)->updateBlockLivenessInfo()) {
274                 changed = true;
275             }
276         }
277     }
278
279     livenessCalculated_ = true;
280 }
281
282 // This function does two things.
283 // First, it does a backwards iteration over instructions in its
284 // block to calculate its liveness.
285 // At the same time, we cache liveness (which was calculated) in
286 // any instPoints we cover. Since an iP only exists if the user
287 // asked for it, we take its existence to indicate that they'll
288 // also be instrumenting. 
289 void instPoint::calcLiveness() {
290    // Assume that the presence of information means we
291    // did this already.
292    if (postLiveRegisters_.size()) {
293       return;
294    }
295    // First, ensure that the block liveness is done.
296    func()->ifunc()->calcBlockLevelLiveness();
297
298    unsigned width = func()->ifunc()->img()->getObject()->getAddressWidth();
299
300    if (func()->ifunc()->instLevel() == HAS_BR_INDIR)
301    {
302      //Unresolved indirect jumps could go anywhere.  
303      //We'll be the most conservative possible in these cases, since
304      //we're missing control flow.
305      postLiveRegisters_ = (registerSpace::getRegisterSpace(width)->getAllRegs());
306      return;
307    }
308
309    // We know: 
310    //    liveness in at the block level:
311    const bitArray &block_in = block()->llb()->getLivenessIn();
312    //    liveness _out_ at the block level:
313    const bitArray &block_out = block()->llb()->getLivenessOut();
314
315    postLiveRegisters_ = block_out;
316
317    assert(postLiveRegisters_.size());
318
319    // We now want to do liveness analysis for straight-line code. 
320         
321    stats_codegen.startTimer(CODEGEN_LIVENESS_TIMER);
322 #if defined(cap_instruction_api)
323    using namespace Dyninst::InstructionAPI;
324     
325    Address blockBegin = block()->origInstance()->firstInsnAddr();
326    Address blockEnd = block()->origInstance()->endAddr();
327    std::vector<Address> blockAddrs;
328    
329    const unsigned char* insnBuffer = 
330       reinterpret_cast<const unsigned char*>(block()->origInstance()->getPtrToInstruction(blockBegin));
331     
332    InstructionDecoder decoder(insnBuffer, block()->origInstance()->getSize());
333    decoder.setMode(proc()->getAddressWidth() == 8);
334    Address curInsnAddr = blockBegin;
335    do
336    {
337      ReadWriteInfo rw;
338      if(!block()->llb()->cachedLivenessInfo.getLivenessInfo(curInsnAddr, func()->ifunc(), rw))
339      {
340        Instruction::Ptr tmp = decoder.decode(insnBuffer);
341        rw = calcRWSets(tmp, block()->llb(), width);
342        block()->llb()->cachedLivenessInfo.insertInstructionInfo(curInsnAddr, rw, func()->ifunc());
343      }
344      blockAddrs.push_back(curInsnAddr);
345      curInsnAddr += rw.insnSize;
346      insnBuffer += rw.insnSize;
347    } while(curInsnAddr < blockEnd);
348     
349     
350    // We iterate backwards over instructions in the block. 
351
352    std::vector<Address>::reverse_iterator current = blockAddrs.rbegin();
353
354    //liveness_printf("%s[%d] instPoint calcLiveness: %d, 0x%lx, 0x%lx\n", 
355    //                FILE__, __LINE__, current != blockAddrs.rend(), *current, addr());
356
357    while(current != blockAddrs.rend() && *current > addr())
358    {
359       // Cache it in the instPoint we just covered (if such exists)
360       instPoint *possiblePoint = func()->findInstPByAddr(*current);
361       if (possiblePoint) {
362          if (possiblePoint->postLiveRegisters_.size() == 0) {
363             possiblePoint->postLiveRegisters_ = postLiveRegisters_;
364          }
365       }
366       
367       ReadWriteInfo rwAtCurrent;
368       if(block()->llb()->cachedLivenessInfo.getLivenessInfo(*current, func()->ifunc(), rwAtCurrent))
369       {
370         liveness_printf("%s[%d] Calculating liveness for iP 0x%lx, insn at 0x%lx\n",
371                         FILE__, __LINE__, addr(), *current);
372         liveness_cerr << "        " << "?XXXXXXXXMMMMMMMMRNDITCPAZSOF11111100DSBSBDCA" << endl;
373         liveness_cerr << "        " << "?7654321076543210FTFFFFFFFFFP54321098IIPPXXXX" << endl;
374         liveness_cerr << "Pre:    " << postLiveRegisters_ << endl;
375         
376         postLiveRegisters_ &= (~rwAtCurrent.written);
377         postLiveRegisters_ |= rwAtCurrent.read;
378         liveness_cerr << "Post:   " << postLiveRegisters_ << endl;
379       
380         ++current;
381       }
382       else
383       {
384         Instruction::Ptr tmp = decoder.decode((const unsigned char*)(block()->origInstance()->getPtrToInstruction(*current)));
385         rwAtCurrent = calcRWSets(tmp, block()->llb(), width);
386         assert(!"SERIOUS ERROR: read/write info cache state inconsistent");
387         liveness_printf("%s[%d] Calculating liveness for iP 0x%lx, insn at 0x%lx\n",
388                         FILE__, __LINE__, addr(), *current);
389         liveness_cerr << "Pre:  " << postLiveRegisters_ << endl;
390         
391         postLiveRegisters_ &= (~rwAtCurrent.written);
392         postLiveRegisters_ |= rwAtCurrent.read;
393         liveness_cerr << "Post: " << postLiveRegisters_ << endl;
394         
395         ++current;
396       }
397       
398    }
399 #else
400    // We iterate backwards over instructions in the block. 
401
402    InstrucIter ii(block());
403
404    // set to the last instruction in the block; setCurrentAddress handles the x86
405    // ii's inability to be a random-access iterator
406    ii.setCurrentAddress(block()->origInstance()->lastInsnAddr());
407
408     
409    //liveness_printf("%s[%d] instPoint calcLiveness: %d, 0x%lx, 0x%lx\n", 
410    //                FILE__, __LINE__, ii.hasPrev(), *ii, addr());
411
412    while(ii.hasPrev() && (*ii > addr())) {
413
414       // Cache it in the instPoint we just covered (if such exists)
415       instPoint *possiblePoint = func()->findInstPByAddr(*ii);
416       if (possiblePoint) {
417          if (possiblePoint->postLiveRegisters_.size() == 0) {
418             possiblePoint->postLiveRegisters_ = postLiveRegisters_;
419          }
420       }
421       ReadWriteInfo regsAffected = calcRWSets(ii, block()->llb(), width);
422
423       //liveness_printf("%s[%d] Calculating liveness for iP 0x%lx, insn at 0x%lx\n",
424       //               FILE__, __LINE__, addr(), *ii);
425       //liveness_cerr << "Pre: " << postLiveRegisters_ << endl;
426
427       postLiveRegisters_ &= (~regsAffected.written);
428       postLiveRegisters_ |= regsAffected.read;
429       //liveness_cerr << "Post: " << postLiveRegisters_ << endl;
430
431       --ii;
432    }
433 #endif // defined(cap_instruction_api)
434    stats_codegen.stopTimer(CODEGEN_LIVENESS_TIMER);
435
436    assert(postLiveRegisters_.size());
437
438    return;
439 }
440
441
442 // It'd be nice to do the calcLiveness here, but it's defined as const...
443 bitArray instPoint::liveRegisters(callWhen when) {
444     // postLiveRegisters_ is our _output_ liveness. If the 
445     // instrumentation is pre-point, we need to update it with
446     // the effects of this instruction.
447
448     unsigned width = func()->ifunc()->img()->getObject()->getAddressWidth();
449
450     // Override: if we have an unparsed jump table in the _function_,
451     // return "everything could be live".
452     if (func()->ifunc()->instLevel() == HAS_BR_INDIR ||
453         func()->ifunc()->instLevel() == UNINSTRUMENTABLE) {
454         bitArray allOn(registerSpace::getBitArray().size());
455         allOn.set();
456         return allOn;
457     }
458         
459     calcLiveness();
460
461     if ((when == callPostInsn) ||
462         (when == callBranchTargetInsn)) {
463         return postLiveRegisters_;
464     }
465     assert(when == callPreInsn);
466
467     bitArray ret(postLiveRegisters_);
468
469     ReadWriteInfo curInsnRW;
470     if(!block()->llb()->cachedLivenessInfo.getLivenessInfo(addr(), func()->ifunc(), curInsnRW))
471     {
472 #if defined(cap_instruction_api)
473       using namespace Dyninst::InstructionAPI;
474       
475       InstructionDecoder decoder;
476       decoder.setMode(proc()->getAddressWidth() == 8);
477       const unsigned char* bufferToDecode =
478       reinterpret_cast<const unsigned char*>(proc()->getPtrToInstruction(addr()));
479       Instruction::Ptr currentInsn = decoder.decode(bufferToDecode);
480
481       curInsnRW = calcRWSets(currentInsn, block()->llb(), width);
482
483 #else
484     // We need to do one more step.
485     // Get the current instruction iterator.
486       InstrucIter ii(block());
487       ii.setCurrentAddress(addr());
488
489       curInsnRW = calcRWSets(ii, block()->llb(), width);
490
491 #endif // defined(cap_instruction_api)
492     }
493     
494     ret &= (~curInsnRW.written);
495     ret |= curInsnRW.read;
496
497     liveness_printf("Liveness out for instruction at 0x%lx\n",
498                       addr());
499     liveness_cerr << "        " << "?XXXXXXXXMMMMMMMMRNDITCPAZSOF11111100DSBSBDCA" << endl;
500     liveness_cerr << "        " << "?7654321076543210FTFFFFFFFFFP54321098IIPPXXXX" << endl;
501     liveness_cerr << "Read    " << curInsnRW.read << endl;
502     liveness_cerr << "Written " << curInsnRW.written << endl;
503     liveness_cerr << "Live    " << ret << endl;
504
505     return ret;
506 }
507
508
509 #if defined(cap_instruction_api)
510 ReadWriteInfo calcRWSets(Instruction::Ptr curInsn, image_basicBlock* blk, unsigned int width)
511 {
512   ReadWriteInfo ret;
513   ret.read = registerSpace::getBitArray();
514   ret.written = registerSpace::getBitArray();
515   ret.insnSize = curInsn->size();
516   
517   std::set<RegisterAST::Ptr> cur_read, cur_written;
518   curInsn->getReadSet(cur_read);
519   curInsn->getWriteSet(cur_written);
520   //liveness_printf("Read registers: ");
521       
522   for (std::set<RegisterAST::Ptr>::const_iterator i = cur_read.begin(); 
523        i != cur_read.end(); i++) 
524   {
525     //liveness_printf("%s ", (*i)->format().c_str());
526     ret.read[convertRegID(IA32Regs((*i)->getID()))] = true;
527   }
528   //liveness_printf("\nWritten registers: ");
529       
530   for (std::set<RegisterAST::Ptr>::const_iterator i = cur_written.begin(); 
531        i != cur_written.end(); i++) {
532     //liveness_printf("%s ", (*i)->format().c_str());
533     ret.written[convertRegID(IA32Regs((*i)->getID()))] = true;
534   }
535   //liveness_printf("\n");
536   InsnCategory category = curInsn->getCategory();
537   switch(category)
538   {
539   case c_CallInsn:
540     ret.read |= (registerSpace::getRegisterSpace(width)->getCallReadRegisters());
541     ret.written |= (registerSpace::getRegisterSpace(width)->getCallWrittenRegisters());
542     break;
543   case c_ReturnInsn:
544     ret.read |= (registerSpace::getRegisterSpace(width)->getReturnReadRegisters());
545     // Nothing written implicitly by a return
546     break;
547   case c_BranchInsn:
548     if(!curInsn->allowsFallThrough() && blk->isExitBlock())
549     {
550       //Tail call, union of call and return
551       ret.read |= ((registerSpace::getRegisterSpace(width)->getCallReadRegisters()) |
552                    (registerSpace::getRegisterSpace(width)->getReturnReadRegisters()));
553       ret.written |= (registerSpace::getRegisterSpace(width)->getCallWrittenRegisters());
554     }
555     break;
556   default:
557     {
558       entryID cur_op = curInsn->getOperation().getID();
559       if(cur_op == e_syscall)
560       {
561         ret.read |= (registerSpace::getRegisterSpace(width)->getSyscallReadRegisters());
562         ret.written |= (registerSpace::getRegisterSpace(width)->getSyscallWrittenRegisters());
563       }
564     }
565     break;
566   }
567   return ret;
568 }
569
570 #else // POWER
571
572 ReadWriteInfo calcRWSets(InstrucIter ii, image_basicBlock* blk, unsigned int width)
573 {
574   ReadWriteInfo ret;
575   ret.read = registerSpace::getBitArray();
576   ret.written = registerSpace::getBitArray();
577   std::set<Register> tmpRead;
578   std::set<Register> tmpWritten;
579   ii.getAllRegistersUsedAndDefined(tmpRead, tmpWritten);
580   
581   for (std::set<Register>::const_iterator i = tmpRead.begin(); 
582        i != tmpRead.end(); i++) {
583     ret.read[*i] = true;
584   }
585   for (std::set<Register>::const_iterator i = tmpWritten.begin(); 
586        i != tmpWritten.end(); i++) {
587     ret.written[*i] = true;
588   }
589   
590   // TODO "If trusting the ABI..."
591   // Otherwise we should go interprocedural
592   if (ii.isACallInstruction()) {
593     ret.read |= (registerSpace::getRegisterSpace(width)->getCallReadRegisters());
594     ret.written |= (registerSpace::getRegisterSpace(width)->getCallWrittenRegisters());
595   }
596   if (ii.isAReturnInstruction()) {
597     ret.read |= (registerSpace::getRegisterSpace(width)->getReturnReadRegisters());
598     // Nothing written implicitly by a return
599   }
600   if (ii.isAJumpInstruction() && blk->isExitBlock())
601   {
602     //Tail call, union of call and return
603     ret.read |= ((registerSpace::getRegisterSpace(width)->getCallReadRegisters()) |
604              (registerSpace::getRegisterSpace(width)->getReturnReadRegisters()));
605     ret.written |= (registerSpace::getRegisterSpace(width)->getCallWrittenRegisters());
606   }
607   if (ii.isSyscall()) {
608     ret.read |= (registerSpace::getRegisterSpace(width)->getSyscallReadRegisters());
609     ret.written |= (registerSpace::getRegisterSpace(width)->getSyscallWrittenRegisters());
610   }
611   return ret;
612 }
613
614 #endif // cap_instruction_api
615 #endif // cap_liveness