mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 16:17:05 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@150878 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			154 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //===-- SPUNopFiller.cpp - Add nops/lnops to align the pipelines ----------===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // The final pass just before assembly printing. This pass is the last
 | |
| // checkpoint where nops and lnops are added to the instruction stream to 
 | |
| // satisfy the dual issue requirements. The actual dual issue scheduling is 
 | |
| // done (TODO: nowhere, currently)
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "SPU.h"
 | |
| #include "SPUTargetMachine.h"
 | |
| #include "llvm/CodeGen/MachineFunctionPass.h"
 | |
| #include "llvm/CodeGen/MachineInstrBuilder.h"
 | |
| #include "llvm/Target/TargetInstrInfo.h"
 | |
| #include "llvm/Support/Debug.h"
 | |
| #include "llvm/Support/raw_ostream.h"
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| namespace {
 | |
|   struct SPUNopFiller : public MachineFunctionPass {
 | |
| 
 | |
|     TargetMachine &TM;
 | |
|     const TargetInstrInfo *TII;
 | |
|     const InstrItineraryData *IID;
 | |
|     bool isEvenPlace;  // the instruction slot (mem address) at hand is even/odd
 | |
| 
 | |
|     static char ID;
 | |
|     SPUNopFiller(TargetMachine &tm) 
 | |
|       : MachineFunctionPass(ID), TM(tm), TII(tm.getInstrInfo()), 
 | |
|         IID(tm.getInstrItineraryData()) 
 | |
|     {
 | |
|       DEBUG( dbgs() << "********** SPU Nop filler **********\n" ; );
 | |
|     }
 | |
| 
 | |
|     virtual const char *getPassName() const {
 | |
|       return "SPU nop/lnop Filler";
 | |
|     }
 | |
| 
 | |
|     void runOnMachineBasicBlock(MachineBasicBlock &MBB);
 | |
| 
 | |
|     bool runOnMachineFunction(MachineFunction &F) {
 | |
|       isEvenPlace = true; //all functions get an .align 3 directive at start 
 | |
|       for (MachineFunction::iterator FI = F.begin(), FE = F.end();
 | |
|            FI != FE; ++FI)
 | |
|         runOnMachineBasicBlock(*FI);
 | |
|       return true; //never-ever do any more modifications, just print it!
 | |
|     }
 | |
| 
 | |
|     typedef enum { none   = 0, // no more instructions in this function / BB
 | |
|                    pseudo = 1, // this does not get executed
 | |
|                    even   = 2, 
 | |
|                    odd    = 3 } SPUOpPlace;
 | |
|     SPUOpPlace getOpPlacement( MachineInstr &instr );
 | |
| 
 | |
|   };
 | |
|   char SPUNopFiller::ID = 0;
 | |
| 
 | |
| } 
 | |
| 
 | |
| // Fill a BasicBlock to alignment. 
 | |
| // In the assebly we align the functions to 'even' adresses, but
 | |
| // basic blocks have an implicit alignmnet. We hereby define 
 | |
| // basic blocks to have the same, even, alignment.
 | |
| void SPUNopFiller::
 | |
| runOnMachineBasicBlock(MachineBasicBlock &MBB) 
 | |
| {
 | |
|   assert( isEvenPlace && "basic block start from odd address");
 | |
|   for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I)
 | |
|   {
 | |
|     SPUOpPlace this_optype, next_optype;
 | |
|     MachineBasicBlock::iterator J = I;
 | |
|     J++;
 | |
| 
 | |
|     this_optype = getOpPlacement( *I );
 | |
|     next_optype = none;
 | |
|     while (J!=MBB.end()){
 | |
|       next_optype = getOpPlacement( *J );
 | |
|       ++J;
 | |
|       if (next_optype != pseudo ) 
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     // padd: odd(wrong), even(wrong), ...
 | |
|     // to:   nop(corr), odd(corr), even(corr)...
 | |
|     if( isEvenPlace && this_optype == odd && next_optype == even ) {
 | |
|       DEBUG( dbgs() <<"Adding NOP before: "; );
 | |
|       DEBUG( I->dump(); );
 | |
|       BuildMI(MBB, I, I->getDebugLoc(), TII->get(SPU::ENOP));
 | |
|       isEvenPlace=false;
 | |
|     }
 | |
|     
 | |
|     // padd: even(wrong), odd(wrong), ...
 | |
|     // to:   lnop(corr), even(corr), odd(corr)...
 | |
|     else if ( !isEvenPlace && this_optype == even && next_optype == odd){
 | |
|       DEBUG( dbgs() <<"Adding LNOP before: "; );
 | |
|       DEBUG( I->dump(); );
 | |
|       BuildMI(MBB, I, I->getDebugLoc(), TII->get(SPU::LNOP));
 | |
|       isEvenPlace=true;
 | |
|     }
 | |
|       
 | |
|     // now go to next mem slot
 | |
|     if( this_optype != pseudo )
 | |
|       isEvenPlace = !isEvenPlace;    
 | |
| 
 | |
|   }
 | |
| 
 | |
|   // padd basicblock end
 | |
|   if( !isEvenPlace ){
 | |
|     MachineBasicBlock::iterator J = MBB.end();
 | |
|     J--;
 | |
|     if (getOpPlacement( *J ) == odd) {
 | |
|       DEBUG( dbgs() <<"Padding basic block with NOP\n"; );
 | |
|       BuildMI(MBB, J, J->getDebugLoc(), TII->get(SPU::ENOP));
 | |
|     }  
 | |
|     else {
 | |
|       J++;
 | |
|       DEBUG( dbgs() <<"Padding basic block with LNOP\n"; );
 | |
|       BuildMI(MBB, J, DebugLoc(), TII->get(SPU::LNOP));
 | |
|     }
 | |
|     isEvenPlace=true;
 | |
|   }
 | |
| }
 | |
| 
 | |
| FunctionPass *llvm::createSPUNopFillerPass(SPUTargetMachine &tm) {
 | |
|   return new SPUNopFiller(tm);
 | |
| }
 | |
| 
 | |
| // Figure out if 'instr' is executed in the even or odd pipeline
 | |
| SPUNopFiller::SPUOpPlace 
 | |
| SPUNopFiller::getOpPlacement( MachineInstr &instr ) {
 | |
|   int sc = instr.getDesc().getSchedClass();
 | |
|   const InstrStage *stage = IID->beginStage(sc);
 | |
|   unsigned FUs = stage->getUnits();
 | |
|   SPUOpPlace retval;
 | |
| 
 | |
|   switch( FUs ) {
 | |
|     case 0: retval = pseudo; break;
 | |
|     case 1: retval = odd;    break;
 | |
|     case 2: retval = even;   break;
 | |
|     default: retval= pseudo; 
 | |
|              assert( false && "got unknown FuncUnit\n");
 | |
|              break;
 | |
|   };
 | |
|   return retval;
 | |
| }
 |