├── .gitignore ├── Makefile ├── PrepareSyn ├── Makefile ├── ModuleSchedulerDriver.cpp ├── ModuleSchedulerDriver.h ├── instPriority.cpp ├── instPriority.h ├── parallelPass.cpp ├── parallelPass.h ├── reduceWordWidth.cpp ├── reduceWordWidth.h ├── removeAlloca.cpp ├── removeAlloca.h ├── subscriptDetect.cpp ├── subscriptDetect.h ├── subscripts.cpp └── subscripts.h ├── README.md ├── Synthesis ├── Makefile ├── Opcodes.cpp ├── Opcodes.h ├── VBackend.cpp ├── VTargetMachine.h ├── abstractHWOpcode.cpp ├── abstractHWOpcode.h ├── designScorer.cpp ├── designScorer.h ├── globalVarsRegistry.cpp ├── globalVarsRegistry.h ├── instPriority.cpp ├── instPriority.h ├── intrinsics.cpp ├── intrinsics.h ├── listScheduler.cpp ├── listScheduler.h ├── verilogLang.cpp └── verilogLang.h ├── license.txt ├── params.cpp ├── params.h ├── utils.h └── vcc.sh /.gitignore: -------------------------------------------------------------------------------- 1 | */*.d 2 | */*.lo 3 | */*.o 4 | .libs 5 | */Release/ 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ##===- lib/Transforms/Makefile -----------------------------*- Makefile -*-===## 2 | # 3 | # The LLVM Compiler Infrastructure 4 | # 5 | # This file was developed by the LLVM research group and is distributed under 6 | # the University of Illinois Open Source License. See LICENSE.TXT for details. 7 | # 8 | ##===----------------------------------------------------------------------===## 9 | 10 | LEVEL = ../../.. 11 | PARALLEL_DIRS = PrepareSyn Synthesis 12 | 13 | include $(LEVEL)/Makefile.common 14 | 15 | -------------------------------------------------------------------------------- /PrepareSyn/Makefile: -------------------------------------------------------------------------------- 1 | ##===- lib/Transforms/Scalar/Makefile ----------------------*- Makefile -*-===## 2 | # 3 | # The LLVM Compiler Infrastructure 4 | # 5 | # This file was developed by the LLVM research group and is distributed under 6 | # the University of Illinois Open Source License. See LICENSE.TXT for details. 7 | # 8 | ##===----------------------------------------------------------------------===## 9 | 10 | LEVEL = ../../../.. 11 | LIBRARYNAME = LLVMPrepareSynthesis 12 | LOADABLE_MODULE = 1 13 | #BUILD_ARCHIVE = 1 14 | BUILT_SOURCES = ../params.cpp 15 | 16 | include $(LEVEL)/Makefile.common 17 | 18 | -------------------------------------------------------------------------------- /PrepareSyn/ModuleSchedulerDriver.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "llvm/Pass.h" 3 | #include "llvm/Function.h" 4 | #include "llvm/Instructions.h" 5 | #include "llvm/Constants.h" 6 | #include "llvm/ADT/StringExtras.h" 7 | #include "llvm/Support/Streams.h" 8 | #include "llvm/Module.h" 9 | #include "llvm/ADT/Statistic.h" 10 | #include "llvm/Analysis/LoopInfo.h" 11 | #include "llvm/ADT/SmallVector.h" 12 | #include "llvm/Support/CFG.h" 13 | #include "llvm/DerivedTypes.h" 14 | #include "llvm/Support/InstIterator.h" 15 | #include "llvm/Transforms/Utils/Cloning.h" 16 | 17 | #include 18 | #include 19 | 20 | #include "instPriority.h" 21 | 22 | #include "../utils.h" 23 | #include "ModuleSchedulerDriver.h" 24 | #include "subscripts.h" 25 | 26 | namespace xVerilog { 27 | 28 | 29 | bool ModuloSchedulerDriverPass::loop_is_ms_able(Loop* loop) { 30 | // must have a pre-header 31 | if (!loop->getLoopPreheader()) return false; 32 | // must have only one block 33 | if (1 != loop->getBlocks().size()) return false; 34 | 35 | // For each BasicBlock in this loop 36 | for (Loop::block_iterator bbit = loop->block_begin(); bbit != loop->block_end(); ++bbit) { 37 | // Get all of the Load addresses and all of the Store addresses 38 | std::vector array_stores = getAllArrayAccess(*bbit,true); 39 | std::vector array_loads = getAllArrayAccess(*bbit,false); 40 | // Make sure we do not read and write from the same array 41 | for (std::vector::iterator arit = array_stores.begin(); 42 | arit != array_stores.end(); ++arit) { 43 | if (std::find(array_loads.begin(), array_loads.end(), *arit) != array_loads.end()) { 44 | //cerr<<"Unable to operate MS since we read and write to the same array in:"<<**bbit; 45 | return false; 46 | } 47 | } 48 | 49 | for (BasicBlock::iterator it = (*bbit)->begin(); it!= (*bbit)->end(); ++it) { 50 | if (PHINode* phi = dyn_cast(it)) { 51 | // For each incoming edge on the PHINode 52 | unsigned int incoming = phi->getNumIncomingValues(); 53 | for (unsigned int i=0; i< incoming; i++) { 54 | // If our PHINode depends on another PHINode. 55 | if (dyn_cast(phi->getIncomingValue(i))) return false; 56 | } 57 | } 58 | } 59 | 60 | // we have no bad instructions (call, return, etc) 61 | for (BasicBlock::iterator it = (*bbit)->begin(); it!= (*bbit)->end(); ++it) { 62 | if (dyn_cast(it)) return false; 63 | if (dyn_cast(it)) return false; 64 | if (dyn_cast(it)) return false; 65 | if (dyn_cast(it)) return false; 66 | if (dyn_cast(it)) return false; 67 | if (dyn_cast(it)) return false; 68 | if (dyn_cast(it)) return false; 69 | if (dyn_cast(it)) return false; 70 | if (dyn_cast(it)) return false; 71 | if (dyn_cast(it)) return false; 72 | } 73 | } 74 | return true; 75 | } 76 | 77 | 78 | Value* ModuloSchedulerDriverPass::copyLoopBodyToHeader(Instruction* inst, 79 | Instruction* induction, BasicBlock* header, int offset){ 80 | 81 | // Holds the body of the interesting loop 82 | BasicBlock *body = inst->getParent(); 83 | 84 | assert(header && "Header is null"); 85 | assert(header->getTerminator() && "Header has no terminator"); 86 | 87 | // Maps the old instructions to the new Instructions 88 | DenseMap ValueMap; 89 | // Do the actual clone 90 | stringstream iname; 91 | iname<<"___"<begin(); it != newBB->end(); ++it) { 97 | for (Instruction::op_iterator ops = (it)->op_begin(); ops != (it)->op_end(); ++ops) { 98 | if (ValueMap.end() != ValueMap.find(*ops)) { 99 | //*ops = ValueMap[*ops]; 100 | it->replaceUsesOfWith(*ops, ValueMap[*ops]); 101 | } 102 | } 103 | } 104 | 105 | // Fixing the PHI nodes since they are no longer needed 106 | for (BasicBlock::iterator it = newBB->begin(); it != newBB->end(); ++it) { 107 | if (PHINode *phi = dyn_cast(it)) { 108 | // Taking the preheader entryfrom the PHI node 109 | 110 | Value* prevalue = phi->getIncomingValue(phi->getBasicBlockIndex(header)); 111 | assert(prevalue && "no prevalue. Don't know what to do"); 112 | 113 | // If we are handling a PHI node which is the induction index ? A[PHI(i,0)] ? 114 | // If so, turn it into A[i + offset] 115 | if (ValueMap[induction] == phi) { 116 | Instruction *add = subscripts::incrementValue(prevalue, offset); 117 | //add->insertBefore(phi); This is the same as next line (compiles on LLVM2.1) 118 | phi->getParent()->getInstList().insert(phi, add); 119 | phi->replaceAllUsesWith(add); 120 | } else { 121 | // eliminating the PHI node all together 122 | // This is just a regular variable or constant. No need to increment 123 | // the index. 124 | phi->replaceAllUsesWith(prevalue); 125 | } 126 | } 127 | } 128 | 129 | // Move all non PHI and non terminator instructions into the header. 130 | while (!newBB->getFirstNonPHI()->isTerminator()) { 131 | Instruction* inst = newBB->getFirstNonPHI(); 132 | if (dyn_cast(inst)) { 133 | inst->eraseFromParent(); 134 | } else { 135 | inst->moveBefore(header->getTerminator()); 136 | } 137 | } 138 | newBB->dropAllReferences(); 139 | return ValueMap[inst]; 140 | } 141 | 142 | bool ModuloSchedulerDriverPass::runOnLoop(Loop *IncomingLoop, LPPassManager &LPM_Ref) { 143 | 144 | subscripts subs(IncomingLoop); 145 | 146 | if (!loop_is_ms_able(IncomingLoop) ) return false; 147 | 148 | // The header before the parallelized loop will be placed here 149 | BasicBlock* preheader = IncomingLoop->getLoopPreheader(); 150 | assert(preheader && "Unable to get a hold of the preheader"); 151 | 152 | // Balance all BasicBlocks in this loop 153 | for (Loop::block_iterator it=IncomingLoop->block_begin(); it!=IncomingLoop->block_end();++it) { 154 | duplicateValuesWithMultipleUses(*it,subs.getInductionVar()); 155 | } 156 | 157 | // For each BB in loop 158 | for (Loop::block_iterator it=IncomingLoop->block_begin(); it!=IncomingLoop->block_end();++it) { 159 | instructionPriority ip(*it); 160 | (*it)->setName("PipelinedLoop"); 161 | 162 | // ++++++++ Preheader part +++++++++ 163 | // Make a copy of the body for each instruction. Place a pointer to the 164 | // parallel cloned instruction in the map below. Later on we will replace it 165 | // with a PHINode. 166 | DenseMap InstToPreheader; 167 | 168 | // For each Instruction in body of the loop, clone, store, etc. 169 | for (BasicBlock::iterator ib = (*it)->begin(), eb = (*it)->end(); ib!=eb; ++ib) { 170 | // If this is NOT a phi node 171 | if (!dyn_cast(ib)) { 172 | // Get the priority of the instruction 173 | unsigned int p = ip.getPriority(ib); 174 | // This is the header version of each variable that goes into a PHI node. 175 | // The other edge needs to come from the 'prev' iteration 176 | // We subtract -1 because this is one iteration before 177 | // Store the result into the map of the cloned 178 | InstToPreheader[ib] = copyLoopBodyToHeader(ib, subs.getInductionVar(), preheader, p-1); 179 | } 180 | } 181 | 182 | // ++++++++ Loop body part +++++++++ 183 | // For each of the cloned increment the indexs if needed and place the PHINode. 184 | for (BasicBlock::iterator ib = (*it)->begin(), eb = (*it)->end(); ib!=eb; ++ib) { 185 | // If this is NOT a phi node 186 | if (!dyn_cast(ib)) { 187 | unsigned int p = ip.getPriority(ib); 188 | 189 | // If this variable is not dependent on i (not i:=i+1) 190 | // then we need to replace each i to i+5 ... 191 | // We also do not need to create a PHI node, etc. 192 | if (!subs.isUsedByInductionVariable(ib)) { 193 | 194 | incrementInductionVarIfUsed(ib,subs.getInductionVar(),p); 195 | 196 | // Create the new PHI Node to replace the node 197 | if (!dyn_cast(ib) && !ib->isTerminator()) { 198 | std::string newname = "glue" + (*it)->getName(); 199 | 200 | //PHINode* np = PHINode::Create(ib->getType(), "glue", *it); 201 | PHINode* np = PHINode::Create(ib->getType(), newname, *it); 202 | ib->replaceAllUsesWith(np); 203 | np->reserveOperandSpace(2); 204 | np->addIncoming(InstToPreheader[ib], preheader); 205 | np->addIncoming(ib, *it); 206 | np->moveBefore((*it)->begin()); 207 | } 208 | 209 | }// end of if this is not an IV node (i:=i+1) 210 | } 211 | } 212 | } 213 | 214 | eliminateDuplicatedLoads(preheader); 215 | for (Loop::block_iterator it=IncomingLoop->block_begin(); it!=IncomingLoop->block_end();++it) { 216 | eliminateDuplicatedLoads(*it); 217 | for (BasicBlock::iterator in = (*it)->begin(); in != (*it)->end(); ++in) { 218 | foldAddInstructions(in); 219 | } 220 | } 221 | return true; 222 | } 223 | 224 | void ModuloSchedulerDriverPass::incrementInductionVarIfUsed(Instruction* inst, Instruction* ind, int offset) { 225 | // For each of the operands of our instruction 226 | for (Instruction::op_iterator op = inst->op_begin(); op!= inst->op_end(); ++op) { 227 | // if our instruction uses 'i' (the induction var) 228 | if (*op == ind) { 229 | // Add an offset to the induction variable 230 | Instruction *add = subscripts::incrementValue(*op, offset, inst); 231 | // Now our instruction depends on the new offset induction variable ([i+4]). 232 | *op = add; 233 | } 234 | } 235 | } 236 | 237 | void ModuloSchedulerDriverPass::duplicateValuesWithMultipleUses(BasicBlock* bb, Instruction* ind) { 238 | 239 | // While we keep duplicating nodes (and create more possible work), keep going 240 | bool keep_going = false; 241 | do { 242 | keep_going = false; 243 | // For each instruction in this BB 244 | for (BasicBlock::iterator it = bb->begin(); it!= bb->end(); ++it) { 245 | // if it is not the induction variable and it has more than one use 246 | if ((!dyn_cast(it)) && // Do not clone PHINodes 247 | (ind != it) && // Do not clone induction pointer 248 | // Only clone when you have more than one #uses 249 | (instructionPriority::getLocalUses(it,bb) >1)) { 250 | 251 | Instruction* cloned = it->clone(); // duplicate it 252 | it->getParent()->getInstList().insert(it, cloned); 253 | //Can also do: cloned->insertBefore(it); // on newer LLVMS 254 | cloned->setName("cloned"); 255 | instructionPriority::replaceFirstUseOfWith(it, cloned); 256 | // we may have created potential candidates for duplication. 257 | // you have to keep going 258 | keep_going = true; 259 | } 260 | } // foe rach inst 261 | } while (keep_going); 262 | } 263 | 264 | std::vector ModuloSchedulerDriverPass::getAllArrayAccess(BasicBlock* bb, bool store) { 265 | std::vector arrayBases; 266 | // for each instruction 267 | for (BasicBlock::iterator it = bb->begin(); it!= bb->end(); ++it) { 268 | Instruction* inst = it; 269 | // If we calculate an address 270 | if (dyn_cast(inst)) { 271 | Value* arrayBase = inst->getOperand(0); // This is the array base we access 272 | // For each of the users of this address (I assume all users are in this BB) 273 | for (Instruction::use_iterator uit = inst->use_begin(); uit!= inst->use_end(); ++uit) { 274 | // If this is STORE or LOAD (and we are asked for S or L) 275 | if (dyn_cast(uit) && store || dyn_cast(uit) && !store) { 276 | //if (store) cerr<<"Store Found "<<*inst<<**uit; 277 | //if (!store) cerr<<"Load Found "<<*inst<<**uit; 278 | arrayBases.push_back(arrayBase); 279 | } 280 | } 281 | } 282 | } 283 | return arrayBases; 284 | } 285 | 286 | void ModuloSchedulerDriverPass::eliminateDuplicatedLoads(BasicBlock* bb) { 287 | bool found; 288 | do { 289 | found = false; 290 | for (BasicBlock::iterator it0 = bb->begin(); it0 != bb->end(); ++it0) { 291 | for (BasicBlock::iterator it1 = it0; it1 != bb->end(); ++it1) { 292 | if (it0 != it1 && areInstructionsIdentical(it0,it1)) { 293 | it1->replaceAllUsesWith(it0); 294 | it1->eraseFromParent(); 295 | found = true; 296 | break; 297 | } 298 | } 299 | } 300 | } while (found == true); 301 | } 302 | 303 | bool ModuloSchedulerDriverPass::areInstructionsIdentical(Instruction* i1, Instruction* i2) { 304 | // Compare PHINodes 305 | if (i1 == i2) return false; // Do nothing if they are the same 306 | 307 | if ( dyn_cast(i1) && dyn_cast(i2)) { 308 | PHINode *p1 = dyn_cast(i1); 309 | PHINode *p2 = dyn_cast(i2); 310 | unsigned int incoming = p1->getNumIncomingValues(); 311 | 312 | // If the number of incoming edges is different 313 | if (p2->getNumIncomingValues() != incoming) return false; 314 | 315 | // For each edge 316 | for (unsigned int i=0; i< incoming; i++) { 317 | // Compare incoming values and incoming blocks 318 | if (p1->getIncomingValue(i) != p2->getIncomingValue(i)) return false; 319 | if (p1->getIncomingBlock(i) != p2->getIncomingBlock(i)) return false; 320 | } 321 | // PHINodes are identical!!! 322 | return true; 323 | } 324 | 325 | if (i1->getOpcode() == i2->getOpcode()) { 326 | unsigned int operands = i1->getNumOperands(); 327 | if (i2->getNumOperands() != operands) return false; //Different number of operands 328 | for (unsigned int i=0; igetOperand(i) != i2->getOperand(i)) return false; 330 | } 331 | 332 | return true; 333 | 334 | } else return false; 335 | 336 | } 337 | 338 | void ModuloSchedulerDriverPass::foldAddInstructions(Instruction* add) { 339 | if (dyn_cast(add) && add->getOpcode() == Instruction::Add) { 340 | BinaryOperator *bin = dyn_cast(add); 341 | unsigned int bitWidth = cast(bin->getType())->getBitWidth(); 342 | 343 | Value *p0 = add->getOperand(0);//param1 344 | Value *p1 = add->getOperand(1);//param0 345 | if (dyn_cast(p0) && dyn_cast(p1)) { 346 | ConstantInt *c0 = dyn_cast(p0); 347 | ConstantInt *c1 = dyn_cast(p1); 348 | 349 | //TODO:May overflow 350 | unsigned int val = (c0->getValue().getZExtValue() + c1->getValue().getZExtValue()); 351 | ConstantInt *ncon = ConstantInt::get(APInt(bitWidth, val)); 352 | add->replaceAllUsesWith(ncon); 353 | add->eraseFromParent(); 354 | return; 355 | } 356 | 357 | if (ConstantInt *c0 = dyn_cast(p0)) { 358 | if (0 == c0->getValue().getZExtValue()) { 359 | add->replaceAllUsesWith(p1); 360 | add->eraseFromParent(); 361 | return; 362 | } 363 | } 364 | if (ConstantInt *c1 = dyn_cast(p1)) { 365 | if (0 == c1->getValue().getZExtValue()) { 366 | add->replaceAllUsesWith(p0); 367 | add->eraseFromParent(); 368 | return; 369 | } 370 | } 371 | } 372 | } 373 | 374 | 375 | char ModuloSchedulerDriverPass::ID = 0; 376 | RegisterPass XMSX("ms", "Run the modulo scheduler"); 377 | 378 | } //namespace 379 | 380 | 381 | -------------------------------------------------------------------------------- /PrepareSyn/ModuleSchedulerDriver.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_MSCHED_H 3 | #define LLVM_MSCHED_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/DerivedTypes.h" 16 | #include "llvm/Analysis/LoopPass.h" 17 | #include "llvm/Analysis/LoopInfo.h" 18 | #include "llvm/Transforms/Utils/Local.h" 19 | #include "llvm/Transforms/Scalar.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | using namespace llvm; 29 | 30 | using std::set; 31 | using std::map; 32 | using std::vector; 33 | using std::pair; 34 | using std::string; 35 | 36 | namespace xVerilog { 37 | 38 | /* 39 | * The awesome ModuloScheduler pass 40 | */ 41 | class ModuloSchedulerDriverPass : public LoopPass { 42 | 43 | public: 44 | /// needed by LLVM 45 | static char ID; 46 | /** 47 | * @brief C'tor in LLVM style 48 | */ 49 | ModuloSchedulerDriverPass() : LoopPass((intptr_t)&ID) {} 50 | 51 | /** 52 | * @brief Requires LoopInfo analysis and tells llvm that 53 | * we change nothing 54 | * 55 | * @param AU llvm analysis usage internal object 56 | */ 57 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 58 | AU.addRequiredID(LoopSimplifyID); 59 | AU.addPreservedID(LoopSimplifyID); 60 | AU.addRequired(); 61 | } 62 | 63 | void runModuloScheduler(Function *F); 64 | 65 | virtual bool runOnLoop(Loop *IncomingLoop, LPPassManager &LPM_Ref); 66 | 67 | private: 68 | /** 69 | * @brief Checks if we are able to apply MS to this loop. 70 | * 1. Is this loop only one BB 71 | * 2. Are we storing and loading only to different arrays? 72 | * 3. etc (see code) 73 | * 74 | * @param loop The loop to inspect 75 | * 76 | * @return True if we can apply the transformation 77 | */ 78 | bool loop_is_ms_able(Loop* loop); 79 | /** 80 | * @brief Copy the tree of instructions above the current instructions into the 81 | * Preheader. This will create the preheader for the MS. Each of the subscripts 82 | * will be adjusted by the 'offset' parameter. The instruction is also copied. 83 | * Store instructions are not copied. On phi nodes, they are replaced with the value 84 | * thats coming from the preheader. 85 | * 86 | * @param inst the instruction whos 87 | * @param induction the induction variable of the loop (the 'i') 88 | * @param header The 'preheader' of the loop 89 | * @param offset the offset to add to the subscriptions 90 | * @return the new instruction inside the preheader 91 | */ 92 | Value* copyLoopBodyToHeader(Instruction* inst, Instruction* induction, BasicBlock* header, int offset); 93 | /** 94 | * @brief Increments the index as used by MS. It creates a new constant 95 | * and an 'add' instruction and replaces the 'i' reference with the new command. 96 | * Adds a new instruction before 'inst'. 97 | * for example: A[i] -> A[i+offset]. 98 | * 99 | * @param inst The instruction to modify. 100 | * @param ind the induction variable 101 | * @param offset the offset - how much to increment. 102 | */ 103 | void incrementInductionVarIfUsed(Instruction* inst, Instruction* ind, int offset); 104 | /** 105 | * @brief clone all values in this BB which have a use>1. This is done so that 106 | * each instruction will depend on values which are exactly one level above it. 107 | * In the case where two instructions of different depth (in the DAG) depend on a third 108 | * instruction, we can't change the indexing according to the modulo scheduling. 109 | * We only duplicate instructions within this BB. 110 | * 111 | * @param bb the BasicBlock to modify 112 | * @param ind The induction variable 113 | */ 114 | void duplicateValuesWithMultipleUses(BasicBlock* bb, Instruction* ind); 115 | /** 116 | * @brief Return a vector of all of the arrays 117 | * 118 | * For example, This code will return the vector[%array1]: 119 | * %ptr10 = getelementptr i32* %array1, i32 %i ; [#uses=1] 120 | * %tmp41 = load i32* %ptr10, align 4 ; [#uses=1] 121 | * 122 | * @param bb The basic block to search. 123 | * @param store Look for StoreInst commands or LoadInst commands. 124 | * True if Store, False if Load. 125 | * 126 | * @return the std vector with the values. 127 | */ 128 | std::vector getAllArrayAccess(BasicBlock* bb, bool store); 129 | /** 130 | * @brief After MS we often have multiple LoadInst from the same address 131 | * in the array. This pass removes them. 132 | * 133 | * @param bb The BB to scan (This is the body of the loop). 134 | */ 135 | void eliminateDuplicatedLoads(BasicBlock* bb); 136 | /** 137 | * @brief Return True if the operand of both instructions identical. 138 | * (Both take from the same values) 139 | * Implemented:PHINode, GetElementPTR and Load 140 | * 141 | * @param i1 142 | * @param i2 143 | * 144 | * @return True if identical 145 | */ 146 | bool areInstructionsIdentical(Instruction* i1, Instruction* i2); 147 | /** 148 | * @brief If this instruction is a BinaryOperand of type ADD 149 | * and can be optimized to one of the forms: 150 | * = x + 0 151 | * = const + const 152 | * it replaces all values with the optimized add 153 | * 154 | * @param add The instruction to work on. If this is not an ADD inst, do nothing. 155 | */ 156 | void foldAddInstructions(Instruction* add); 157 | }; // class 158 | 159 | 160 | 161 | } //end of namespace 162 | #endif // h guard 163 | -------------------------------------------------------------------------------- /PrepareSyn/instPriority.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "instPriority.h" 3 | 4 | namespace xVerilog { 5 | 6 | string instructionPriority::toString() { 7 | stringstream ss; 8 | 9 | ss<<"InstructionPriority for \""<getName()<<"\"["<begin(); it != BB->end(); ++it) { 13 | if (i == m_depth[it]) ss<<"\t"<<*it<BB = BB; 23 | m_maxDepth = 0; 24 | calculateDeps(); 25 | } 26 | 27 | void instructionPriority::replaceFirstUseOfWith(Instruction* inst, Instruction* cloned) { 28 | for (Instruction::use_iterator it = inst->use_begin(); it!= inst->use_end(); ++it) { 29 | if (Instruction* dep = dyn_cast(it)) { 30 | if (dep->getParent() == cloned->getParent()) { 31 | // replace the use with 'cloned' instruction 32 | for (Instruction::op_iterator ops = it->op_begin(); ops!= it->op_end(); ++ops) { 33 | if (inst==*ops) { 34 | *ops = cloned; 35 | return; // Only do first use 36 | } 37 | } 38 | } // Only if we are in the same BasicBlock 39 | } //"If it's not instruction, what is it?"<<*it; 40 | } 41 | assert(0 && "Unable to find original value to replace"); 42 | } 43 | 44 | unsigned int instructionPriority::getLocalUses(const Instruction* inst, const BasicBlock* BB) { 45 | unsigned int uses = 0; 46 | // For all of the users of this instructions 47 | for (Instruction::use_const_iterator it = inst->use_begin(); it!= inst->use_end(); ++it) { 48 | // Which are really instructions 49 | if (const Instruction* d = dyn_cast(*it)) { 50 | // And are in this basic block 51 | if (d->getParent() == BB) uses++; 52 | } 53 | } 54 | return uses; 55 | } 56 | 57 | unsigned int instructionPriority::getLatencyForInstruction(const Instruction* inst) const { 58 | return 1; 59 | } 60 | 61 | set instructionPriority::getDependencies(const Instruction* inst) { 62 | set deps; 63 | 64 | // We do not count PHINodes because they may create cyclic dependencies. 65 | // We only want to get dependencies which are within this BB's iteration. 66 | if (dyn_cast(inst)) { 67 | return deps; 68 | } 69 | 70 | // for all deps 71 | for (User::const_op_iterator dep_iter = inst->op_begin(); 72 | dep_iter != inst->op_end(); ++dep_iter){ 73 | // if this dep is an instruction rather then a parameter 74 | if (const Instruction* dep = dyn_cast(*dep_iter)) { 75 | if (dep->getParent() == BB) 76 | deps.insert(dep); 77 | } 78 | } 79 | return deps; 80 | } 81 | 82 | 83 | void instructionPriority::calculateDeps() { 84 | set to_update; 85 | 86 | // Setup map for iterations 87 | for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; ++I) { 88 | if (0 == getLocalUses(I,BB)) { 89 | m_depth[I] = 0; 90 | to_update.insert(I); 91 | } else { 92 | // unused instructions are set to layer zero 93 | // which is the last layer 94 | m_depth[I] = 0; 95 | } 96 | } 97 | 98 | assert (m_depth.size() == BB->size() && "Map and BB are in different sizes"); 99 | // While there are opcodes to update 100 | // do the following iterations 101 | while(0 != to_update.size()) { 102 | 103 | // what to update next round 104 | set next_update; 105 | 106 | // for all instructions in the update list 107 | for (set::iterator it = to_update.begin(); 108 | it!= to_update.end(); ++it) { 109 | 110 | // for all instructions in the dependency list 111 | set deps = getDependencies(*it); 112 | for (set::iterator dp = deps.begin(); 113 | dp!= deps.end(); ++dp) { 114 | // Each opcode is assigned to the longest distance 115 | // either it's current distance or the path from the 116 | // dependency 117 | 118 | // We create the effect of layers of opcodes where some opcodes 119 | // take more cycles by filling the dependency table with varying 120 | // dependency length. see getLatencyForInstruction 121 | m_depth[*dp] = std::max(m_depth[*it] + getLatencyForInstruction(*it), m_depth[*dp]); 122 | m_maxDepth = std::max(m_depth[*dp], m_maxDepth); 123 | // we need to update the children of this opcode 124 | // in the next iteration 125 | next_update.insert(*dp); 126 | } 127 | } 128 | // prepare next iteration 129 | to_update.clear(); 130 | to_update.insert(next_update.begin(), next_update.end()); 131 | } 132 | } 133 | 134 | } // namespace 135 | -------------------------------------------------------------------------------- /PrepareSyn/instPriority.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_INST_PRIO_H 3 | #define LLVM_INST_PRIO_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/DerivedTypes.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "../utils.h" 25 | 26 | using namespace llvm; 27 | 28 | 29 | namespace xVerilog { 30 | 31 | using std::vector; 32 | using std::map; 33 | 34 | /* 35 | * This class gives a scheduling priority for each one of the instructions 36 | * in a basic block based on a reasonable order. It gives 37 | * instructions which are in the critical pass the first priority. 38 | */ 39 | class instructionPriority { 40 | public: 41 | typedef map InstPriorityMap; 42 | 43 | /* 44 | *C'tor 45 | */ 46 | instructionPriority(const BasicBlock* BB); 47 | 48 | /** 49 | * @brief Debug prints the content of the priority table 50 | * 51 | * @return string with the table in ascii 52 | */ 53 | string toString(); 54 | 55 | /** 56 | * @brief Return the hight of the dependenct tree. 57 | * This is the highest value in the dependency map 58 | * @return max depth 59 | */ 60 | unsigned int getMaxDepth() const {return m_maxDepth;} 61 | 62 | /** 63 | * @brief Return the priority of the instruction in the graph 64 | * @param inst The param to check 65 | * @return the height in the priority graph 66 | */ 67 | unsigned int getPriority(const Instruction* inst) {return m_depth[inst];} 68 | /** 69 | * @brief Returns the number of uses this inst has 70 | * in this basic block 71 | */ 72 | static unsigned int getLocalUses(const Instruction* inst, const BasicBlock* BB); 73 | 74 | /** 75 | * @brief Replace the first use in the use chain with a given version 76 | * 77 | * @param inst 78 | * @param orig 79 | * @param cloned 80 | */ 81 | static void replaceFirstUseOfWith(Instruction* inst, Instruction* cloned); 82 | private: 83 | /** 84 | * @brief Returns the latency in cycles of instruction. 85 | * For example, a MUL may take 5 cycles to complete, add 86 | * may take 2. 87 | * 88 | * @param inst the instruction we want to test 89 | * 90 | * @return Latency in cycles 91 | */ 92 | unsigned int getLatencyForInstruction(const Instruction* inst) const; 93 | 94 | /* 95 | * Return a list of all of the dependencies of instruction 96 | */ 97 | set getDependencies(const Instruction* inst); 98 | 99 | /** 100 | * @brief Calculate the dependencies between the 101 | * different opcodes. Give each one of the nodes a BFS 102 | * score. 103 | */ 104 | void calculateDeps(); 105 | 106 | /// Holds the depth of each of the elements in the graph 107 | InstPriorityMap m_depth; 108 | // Holds the maximum depth of the InstPriorityMap 109 | unsigned int m_maxDepth; 110 | /// hold the BasicBlock 111 | const BasicBlock* BB; 112 | }; //class 113 | 114 | 115 | } //end of namespace 116 | #endif // h guard 117 | -------------------------------------------------------------------------------- /PrepareSyn/parallelPass.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "parallelPass.h" 3 | 4 | #include "llvm/Pass.h" 5 | #include "llvm/Function.h" 6 | #include "llvm/Instructions.h" 7 | #include "llvm/Constants.h" 8 | #include "llvm/ADT/StringExtras.h" 9 | #include "llvm/Support/Streams.h" 10 | #include "llvm/Module.h" 11 | #include "llvm/ADT/Statistic.h" 12 | #include "llvm/ADT/SmallVector.h" 13 | #include "llvm/Support/CFG.h" 14 | #include "llvm/DerivedTypes.h" 15 | 16 | #include 17 | #include 18 | #include "../utils.h" 19 | 20 | namespace xVerilog { 21 | 22 | 23 | bool ParallelPass::isLikelyToBeFatNode(Instruction* inst) { 24 | if (dyn_cast(inst->getOperand(0))) return true; 25 | if (dyn_cast(inst->getOperand(1))) return true; 26 | return false; 27 | } 28 | 29 | void ParallelPass::findAllChildrenOfSameType(llvm::Instruction::BinaryOps type, 30 | Value* inst, vector *nodes, vector *leafs) { 31 | 32 | if (dyn_cast(inst) && inst->hasOneUse()) { 33 | BinaryOperator* bin=(BinaryOperator*) inst; 34 | if (bin->getOpcode() == type) { 35 | // if this is the first node we are processing 36 | // OR is this node is in the save BasicBlock as the first node 37 | if (0==nodes->size() || (*nodes)[0]->getParent() == bin->getParent()) { 38 | nodes->push_back(bin); 39 | findAllChildrenOfSameType(type, bin->getOperand(0), nodes, leafs); 40 | findAllChildrenOfSameType(type, bin->getOperand(1), nodes, leafs); 41 | } 42 | } else leafs->push_back(inst); 43 | } else leafs->push_back(inst); 44 | } 45 | 46 | 47 | bool ParallelPass::floodParallelCommutative(Instruction *inst, 48 | llvm::Instruction::BinaryOps binType) { 49 | vector nodes; 50 | vector leafs; 51 | // Is this an instruction of the correct type (ex: Add)? 52 | if (dyn_cast(inst)) { 53 | BinaryOperator* bin=(BinaryOperator*) inst; 54 | if (bin->getOpcode() != binType) { 55 | return false; 56 | } 57 | } else { 58 | return false; 59 | } 60 | 61 | // Find all children nodes 62 | findAllChildrenOfSameType(binType, inst->getOperand(0), &nodes, &leafs); 63 | findAllChildrenOfSameType(binType, inst->getOperand(1), &nodes, &leafs); 64 | 65 | // if we only found one node then we can't rearrange 66 | // things. return with no change. 67 | if (nodes.size()<3) return false; 68 | 69 | // A map used to create the balanced tree structure 70 | // very much like hoffman tree (just balanced) 71 | map rank_map; 72 | // iterators 73 | vector::iterator node_it = nodes.begin(); 74 | vector::iterator leaf_it = leafs.begin(); 75 | map::iterator map_it; 76 | 77 | // take all the leafs and join them with 'bin' nodes 78 | // creates the first layer of the pyramid 79 | Instruction* last_bin = NULL; 80 | while(leaf_it != leafs.end()) { 81 | // take two leafs, join then with an arithmetic operation 82 | // and store them in the hash table with rank one. 83 | // this is the bottom of the balanced tree 84 | (*node_it)->setOperand(0,*leaf_it); leaf_it++; 85 | (*node_it)->setOperand(1,*leaf_it); leaf_it++; 86 | (*node_it)->setName("lowlevel"); 87 | 88 | if (isLikelyToBeFatNode(*node_it)) { 89 | rank_map[*node_it] = 100; 90 | } else { 91 | rank_map[*node_it] = 1; 92 | } 93 | last_bin = *node_it; 94 | ++node_it; 95 | 96 | assert(last_bin && "unable to find last bin"); 97 | assert((*node_it) && "unable to find node_it"); 98 | // If th number of nodes is odd (we have one leaf left), 99 | // join the last leaf with one of the nodes 100 | if (leaf_it == --leafs.end()) { 101 | (*node_it)->setOperand(0,*leaf_it); leaf_it++; 102 | (*node_it)->setOperand(1,last_bin); 103 | (*node_it)->setName("lowlevelOdd"); 104 | rank_map[*node_it] = 2; 105 | rank_map.erase(last_bin); 106 | node_it++; 107 | } 108 | } 109 | 110 | // We now will reconstruct the rest of the balanced tree, 111 | // joining each two nodes with the lowest ranks together. 112 | // repeat until we only have two nodes 113 | while (node_it != nodes.end()) { 114 | Instruction* minInst1 = NULL; 115 | unsigned int minRank1 = 100000; 116 | Instruction* minInst2 = NULL; 117 | unsigned int minRank2 = 100000; 118 | 119 | // find first node with the lowest rank 120 | for (map_it = rank_map.begin(); map_it!=rank_map.end(); map_it++) { 121 | if ((map_it->second) <= minRank1) { 122 | minInst1 = map_it->first; 123 | minRank1 = map_it->second; 124 | } 125 | } 126 | // find the second node with the lowest rank 127 | for (map_it = rank_map.begin(); map_it!=rank_map.end(); map_it++) { 128 | if ((map_it->first != minInst1) && (map_it->second) <= minRank2) { 129 | minInst2 = map_it->first; 130 | minRank2 = map_it->second; 131 | } 132 | } 133 | 134 | 135 | // assert your findings 136 | assert(minInst1 && "minInst1 is NULL"); 137 | assert(minInst2 && "minInst2 is NULL"); 138 | assert(inst && "inst is NULL"); 139 | assert(minInst1->getParent() == inst->getParent() && "min1 not same bb as inst"); 140 | assert(minInst2->getParent() == inst->getParent() && "min1 not same bb as inst"); 141 | assert(*node_it && "node_it is NULL"); 142 | 143 | // set the arithmetic node to point to two of the ranks 144 | (*node_it)->setOperand(0,minInst1); 145 | (*node_it)->setOperand(1,minInst2); 146 | (*node_it)->setName("pyramid");// give it a somewhat meaningful name 147 | 148 | // place the new node in the map. remove the two old onces from the map 149 | rank_map.erase(minInst1); 150 | rank_map.erase(minInst2); 151 | rank_map[*node_it] = 1 + std::max(minRank1, minRank2); 152 | ++node_it; 153 | minInst2->moveBefore(inst); 154 | minInst1->moveBefore(inst); 155 | } 156 | 157 | // After we have only two nodes left, we set them as the children of the 158 | // head node. Then we move all of the binary nodes just before the headnode 159 | // so the order of the dependencies is correct. 160 | 161 | assert(inst && "inst is NULL"); 162 | assert(rank_map.size() == 2 && "more then two add nodes left at the end of the round!"); 163 | inst->setName("headNode"); 164 | inst->setOperand(0,(rank_map.begin())->first); 165 | inst->setOperand(1,(++rank_map.begin())->first); 166 | 167 | // move all nodes before the last instruction so they 168 | // domminate all dependencies 169 | for (node_it = nodes.begin(); node_it != nodes.end(); ++node_it) { 170 | (*node_it)->moveBefore(inst); 171 | } 172 | 173 | //logPassMessage(__FUNCTION__,__LINE__,"Balanced tree"); 174 | return true; 175 | } 176 | 177 | bool ParallelPass::areAllUsersOfOtherType(Instruction* inst, llvm::Instruction::BinaryOps binType) { 178 | // for all users 179 | for (Instruction::use_iterator us = inst->use_begin(); us!= inst->use_end(); ++us) { 180 | // If this user is a binary operator 181 | if (BinaryOperator* bin = dyn_cast(us)) { 182 | // of the same type 183 | if (bin->getOpcode() == binType) { 184 | return false; 185 | } 186 | } 187 | } 188 | return true; 189 | } 190 | 191 | 192 | void ParallelPass::floodParallel(BasicBlock &BB, llvm::Instruction::BinaryOps binType) { 193 | // start from the end of the basic block. Try to rearrange 194 | // the chain of binary operations. 195 | for (BasicBlock::iterator it=BB.begin();it!=BB.end();++it) { 196 | // Is this an instruction of the correct type (ex: Add)? 197 | BinaryOperator* bin = dyn_cast(it); 198 | if (bin && (bin->getOpcode() == binType)) { 199 | // we only start with head of pyramid 200 | if (areAllUsersOfOtherType(bin,binType)) { 201 | floodParallelCommutative(bin, binType); 202 | } 203 | } 204 | }//BB 205 | } 206 | 207 | bool ParallelPass::runOnFunction(Function &F) { 208 | // for each BasicBlock, parallel the instructions 209 | for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { 210 | ParallelPass::floodParallel(*BB, Instruction::Add); 211 | ParallelPass::floodParallel(*BB, Instruction::Mul); 212 | ParallelPass::floodParallel(*BB, Instruction::Or); 213 | ParallelPass::floodParallel(*BB, Instruction::Xor); 214 | ParallelPass::floodParallel(*BB, Instruction::And); 215 | } 216 | return true; 217 | } 218 | 219 | char ParallelPass::ID = 0; 220 | RegisterPass PXX("parallel_balance", "extract parallelism from expressions"); 221 | 222 | } //namespace 223 | 224 | 225 | -------------------------------------------------------------------------------- /PrepareSyn/parallelPass.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_PARALLEL_PASS_H 3 | #define LLVM_PARALLEL_PASS_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/DerivedTypes.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | using namespace llvm; 25 | 26 | using std::set; 27 | using std::map; 28 | using std::vector; 29 | using std::pair; 30 | using std::string; 31 | 32 | namespace xVerilog { 33 | 34 | /* 35 | */ 36 | class ParallelPass : public FunctionPass { 37 | 38 | public: 39 | /// needed by LLVM 40 | static char ID; 41 | /** 42 | * @brief C'tor in LLVM style 43 | */ 44 | ParallelPass() : FunctionPass((intptr_t)&ID) {} 45 | 46 | /** 47 | * @brief Requires LoopInfo analysis and tells llvm that 48 | * we change nothing 49 | * 50 | * @param AU llvm analysis usage internal object 51 | */ 52 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 53 | AU.setPreservesCFG(); 54 | } 55 | 56 | virtual bool runOnFunction(Function &F); 57 | 58 | public: 59 | /* 60 | * Drives the optimizations described below. 61 | */ 62 | static void floodParallel(BasicBlock &BB, llvm::Instruction::BinaryOps binType); 63 | /* 64 | * This pass rearranges expression trees into a more balanced expression tree. It 65 | * works on trees of the same type (Add, Mul, etc). 66 | */ 67 | static bool floodParallelCommutative(Instruction *inst, llvm::Instruction::BinaryOps binType); 68 | 69 | /** 70 | * @brief Is this instruction likely to be a 'fat' instruction. 71 | * For example, an instruction which has many bits. 72 | * 73 | * @param inst The instruction to test. 74 | * 75 | * @return True if is probably is fat. 76 | */ 77 | static bool isLikelyToBeFatNode(Instruction* inst); 78 | private: 79 | /** 80 | * @param inst Instruction whos children we want to check 81 | * @param binType type to check. Example. Add, Mul, etc. 82 | * @return True of all users of this opcode are of other types (not same binary opcode type) 83 | */ 84 | static bool areAllUsersOfOtherType(Instruction* inst, llvm::Instruction::BinaryOps binType); 85 | /* 86 | * Find all children of an arithmetic expression tree. Put them in two lists. 87 | * One is the nodes of the expression tree, which is of type 'type' (for example ADD). 88 | * The Leafs of the tree (the data) goes into a second list. This adds only 89 | * nodes with use count of one. It adds the leafs and nodes in the order of discovery. 90 | */ 91 | static void findAllChildrenOfSameType(Instruction::BinaryOps type, 92 | Value* inst, vector *nodes, vector *leafs); 93 | }; // class 94 | 95 | 96 | 97 | } //end of namespace 98 | #endif // h guard 99 | -------------------------------------------------------------------------------- /PrepareSyn/reduceWordWidth.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "llvm/Pass.h" 3 | #include "llvm/Function.h" 4 | #include "llvm/Instructions.h" 5 | #include "llvm/Constants.h" 6 | #include "llvm/ADT/StringExtras.h" 7 | #include "llvm/Support/Streams.h" 8 | #include "llvm/Module.h" 9 | #include "llvm/ADT/Statistic.h" 10 | #include "llvm/ADT/SmallVector.h" 11 | #include "llvm/Support/CFG.h" 12 | #include "llvm/DerivedTypes.h" 13 | #include "llvm/Support/InstIterator.h" 14 | 15 | #include 16 | #include 17 | 18 | #include "../utils.h" 19 | #include "reduceWordWidth.h" 20 | 21 | namespace xVerilog { 22 | 23 | bool ReduceWordWidthPass::removeUnusedInstructions(Instruction* inst) { 24 | if (dyn_cast(inst) || dyn_cast(inst) || dyn_cast(inst)) { 25 | if (inst->hasNUses(0)) { 26 | inst->eraseFromParent(); 27 | return true; 28 | } 29 | } 30 | 31 | // remove double casting 32 | if (TruncInst* tr = dyn_cast(inst)) { 33 | if (SExtInst* se = dyn_cast(tr->getOperand(0))) { 34 | Value* v = se->getOperand(0); 35 | unsigned int bitWidth0 = cast(v->getType())->getBitWidth(); 36 | //unsigned int bitWidth1 = cast(se->getType())->getBitWidth(); 37 | unsigned int bitWidth2 = cast(tr->getType())->getBitWidth(); 38 | 39 | if (se->hasOneUse() && bitWidth2 <= bitWidth0) { 40 | tr->setOperand(0,v); 41 | return true; 42 | } 43 | 44 | } 45 | 46 | unsigned int bitWidth1 = cast(tr->getOperand(0)->getType())->getBitWidth(); 47 | unsigned int bitWidth2 = cast(tr->getType())->getBitWidth(); 48 | if (bitWidth1 == bitWidth2 && tr->hasOneUse()) { 49 | tr->replaceAllUsesWith(tr->getOperand(0)); 50 | } 51 | 52 | } 53 | 54 | return false; 55 | } 56 | 57 | bool ReduceWordWidthPass::reduceOperatorWordWidth(Instruction* inst) { 58 | 59 | if (BinaryOperator *calc = dyn_cast(inst)) { 60 | Value *v0 = (calc->getOperand(0)); 61 | Value *v1 = (calc->getOperand(1)); 62 | // if we do a shift right then we loose bits ... 63 | if (calc->getOpcode() == Instruction::LShr) { 64 | if (dyn_cast(v1)) { 65 | ConstantInt *con = dyn_cast(v1); 66 | unsigned int bitWidth = cast(calc->getType())->getBitWidth(); 67 | unsigned int shlVal = con->getValue().getZExtValue(); 68 | unsigned int newBitLen = bitWidth - shlVal; 69 | if (bitWidth != newBitLen) { 70 | CastInst* tv0 = new TruncInst(v0, IntegerType::get(newBitLen),"trunc_shl",calc); 71 | CastInst* tv1 = new TruncInst(v1, IntegerType::get(newBitLen),"trunc_shl",calc); 72 | BinaryOperator* newAnd = BinaryOperator::Create(Instruction::LShr, tv0, tv1,"reduced_and",calc); 73 | CastInst* castedAnd = new SExtInst(newAnd, IntegerType::get(bitWidth),"exand",calc); 74 | calc->replaceAllUsesWith(castedAnd); 75 | return true; 76 | } 77 | } 78 | 79 | } 80 | 81 | 82 | if (calc->getOpcode() == Instruction::Add) { 83 | // if both parameters are 'SExt' then we can resuce them to the smaller size 84 | if ((dyn_cast(v0)) && (dyn_cast(v1))) { 85 | SExtInst* i0 = dyn_cast(v0); 86 | SExtInst* i1 = dyn_cast(v1); 87 | unsigned int currentBitWidth = cast(calc->getType())->getBitWidth(); 88 | unsigned int bitWidth0 = cast(i0->getOperand(0)->getType())->getBitWidth(); 89 | unsigned int bitWidth1 = cast(i1->getOperand(0)->getType())->getBitWidth(); 90 | unsigned int combinedBitWidth = std::max(bitWidth0, bitWidth1) + 1; 91 | if (combinedBitWidth < currentBitWidth) { 92 | 93 | CastInst* cast0 = new SExtInst(i0->getOperand(0), IntegerType::get(combinedBitWidth),"exand",calc); 94 | CastInst* cast1 = new SExtInst(i1->getOperand(0), IntegerType::get(combinedBitWidth),"exand",calc); 95 | BinaryOperator* newAdd = BinaryOperator::Create(Instruction::Add, cast0, cast1,"reduced_and",calc); 96 | CastInst* castedAnd = new SExtInst(newAdd, IntegerType::get(currentBitWidth),"exand",calc); 97 | calc->replaceAllUsesWith(castedAnd); 98 | return true; 99 | } 100 | } 101 | } 102 | 103 | 104 | // If this instruction is an AND instruction which may reduce the size of this ... 105 | if (calc->getOpcode() == Instruction::And) { 106 | if (dyn_cast(v1)) { 107 | Value *t = v1; 108 | v1 = v0; 109 | v0 = t; 110 | } 111 | if (dyn_cast(v0)) { 112 | ConstantInt *con = dyn_cast(v0); 113 | unsigned int bitWidth = cast(calc->getType())->getBitWidth(); 114 | unsigned int bitWidth1 = cast(v1->getType())->getBitWidth(); 115 | unsigned int active = con->getValue().getActiveBits(); 116 | if (bitWidth != active && bitWidth1 != active) { 117 | 118 | CastInst* tv0 = new TruncInst(v0, IntegerType::get(active),"trunc",calc); 119 | CastInst* tv1 = new TruncInst(v1, IntegerType::get(active),"trunc",calc); 120 | BinaryOperator* newAnd = BinaryOperator::Create(Instruction::And, tv0, tv1,"reduced_and",calc); 121 | CastInst* castedAnd = new SExtInst(newAnd, IntegerType::get(bitWidth),"exand",calc); 122 | calc->replaceAllUsesWith(castedAnd); 123 | return true; 124 | } 125 | } 126 | 127 | } 128 | } 129 | return false; 130 | } 131 | 132 | bool ReduceWordWidthPass::runOnFunction(Function &F) { 133 | 134 | bool changed = false; 135 | bool changed_global = false; 136 | 137 | do { 138 | changed = false; 139 | // F is a pointer to a Function instance 140 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 141 | Instruction *inst = &*i; 142 | changed |= reduceOperatorWordWidth(inst); 143 | changed |= removeUnusedInstructions(inst); 144 | } 145 | changed_global |= changed; 146 | } while (changed); 147 | 148 | //if (changed_global) logPassMessage(__FUNCTION__,__LINE__,"Reduced bus width"); 149 | return changed_global; 150 | } 151 | 152 | 153 | 154 | char ReduceWordWidthPass::ID = 0; 155 | RegisterPass RWXX("reduce_bitwidth", "reduce the width of words whenever possible"); 156 | 157 | } //namespace 158 | 159 | 160 | -------------------------------------------------------------------------------- /PrepareSyn/reduceWordWidth.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_REDUCE_WORDWIDTH_H 3 | #define LLVM_REDUCE_WORDWIDTH_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/DerivedTypes.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | using namespace llvm; 25 | 26 | using std::set; 27 | using std::map; 28 | using std::vector; 29 | using std::pair; 30 | using std::string; 31 | 32 | namespace xVerilog { 33 | 34 | /* 35 | */ 36 | class ReduceWordWidthPass : public FunctionPass { 37 | 38 | public: 39 | /// needed by LLVM 40 | static char ID; 41 | /** 42 | * @brief C'tor in LLVM style 43 | */ 44 | ReduceWordWidthPass() : FunctionPass((intptr_t)&ID) {} 45 | 46 | /** 47 | * @brief Requires LoopInfo analysis and tells llvm that 48 | * we change nothing 49 | * 50 | * @param AU llvm analysis usage internal object 51 | */ 52 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 53 | AU.setPreservesCFG(); 54 | } 55 | 56 | bool removeUnusedInstructions(Instruction* inst); 57 | bool reduceOperatorWordWidth(Instruction* inst); 58 | 59 | virtual bool runOnFunction(Function &F); 60 | 61 | private: 62 | 63 | }; // class 64 | 65 | 66 | 67 | } //end of namespace 68 | #endif // h guard 69 | -------------------------------------------------------------------------------- /PrepareSyn/removeAlloca.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "removeAlloca.h" 3 | 4 | #include "llvm/Transforms/Utils/Cloning.h" 5 | #include "llvm/Pass.h" 6 | #include "llvm/Argument.h" 7 | #include "llvm/Function.h" 8 | #include "llvm/Instructions.h" 9 | #include "llvm/Constants.h" 10 | #include "llvm/ADT/StringExtras.h" 11 | #include "llvm/Support/Streams.h" 12 | #include "llvm/Module.h" 13 | #include "llvm/ADT/Statistic.h" 14 | #include "llvm/ADT/SmallVector.h" 15 | #include "llvm/Support/CFG.h" 16 | #include "llvm/DerivedTypes.h" 17 | 18 | #include 19 | #include 20 | #include "../utils.h" 21 | 22 | namespace xVerilog { 23 | 24 | Function* MyCloneFunction(const Function *F, DenseMap &ValueMap, const Type* addedArg, std::string name) { 25 | std::vector ArgTypes; 26 | 27 | // The user might be deleting arguments to the function by specifying them in 28 | // the ValueMap. If so, we need to not add the arguments to the arg ty vector 29 | // 30 | for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) 31 | if (ValueMap.count(I) == 0) // Haven't mapped the argument to anything yet? 32 | ArgTypes.push_back(I->getType()); 33 | 34 | ArgTypes.push_back(addedArg); 35 | 36 | // Create a new function type... 37 | FunctionType *FTy = FunctionType::get(F->getFunctionType()->getReturnType(), ArgTypes, F->getFunctionType()->isVarArg()); 38 | 39 | // Create the new function... 40 | Function *NewF = Function::Create(FTy, F->getLinkage(), F->getName()); 41 | 42 | // Loop over the arguments, copying the names of the mapped arguments over... 43 | Function::arg_iterator DestI = NewF->arg_begin(); 44 | for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) 45 | if (ValueMap.count(I) == 0) { // Is this argument preserved? 46 | DestI->setName(I->getName()); // Copy the name over... 47 | ValueMap[I] = DestI++; // Add mapping to ValueMap 48 | } 49 | 50 | (--NewF->arg_end())->setName(name); 51 | 52 | 53 | std::vector Returns; // Ignore returns cloned... 54 | CloneFunctionInto(NewF, F, ValueMap, Returns, "", 0); 55 | return NewF; 56 | } 57 | 58 | bool removeOneAlloca(Module& M) { 59 | 60 | for (Module::iterator Fit=M.begin(); Fit!=M.end(); ++Fit) { 61 | for (Function::iterator bbit = Fit->begin(); bbit != Fit->end(); ++bbit) { 62 | for (BasicBlock::iterator it = bbit->begin(); it != bbit->end(); ++it) { 63 | if (AllocaInst *alloca = dyn_cast(it)) { 64 | 65 | DenseMap my_map; 66 | const Type* tp = (alloca)->getType(); 67 | std::string name = (alloca)->getName(); 68 | Function* NewFunc = MyCloneFunction(Fit, my_map, tp, name); 69 | 70 | Instruction* newalloca = dynamic_cast(my_map[alloca]); // The alloca in the new function 71 | Argument* arg = --NewFunc->arg_end(); 72 | 73 | newalloca->replaceAllUsesWith(arg); 74 | newalloca->removeFromParent(); 75 | Fit->getParent()->getFunctionList().push_back(NewFunc); 76 | Fit->removeFromParent(); 77 | return true; 78 | 79 | } 80 | } 81 | } 82 | } 83 | 84 | // did not remove anything. We are done. 85 | return false; 86 | } 87 | 88 | 89 | 90 | bool RemoveAllocaPass::runOnModule(Module &M) { 91 | bool changed = false; 92 | while (removeOneAlloca(M)) { 93 | changed = true; 94 | } 95 | 96 | return changed; 97 | } 98 | 99 | char RemoveAllocaPass::ID = 0; 100 | RegisterPass RAX("remove_alloca", "remove allocas"); 101 | 102 | } //namespace 103 | 104 | 105 | -------------------------------------------------------------------------------- /PrepareSyn/removeAlloca.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef REMOVE_ALLOCA_PASS_H 3 | #define REMOVE_ALLOCA_PASS_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/DerivedTypes.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | using namespace llvm; 25 | 26 | using std::set; 27 | using std::map; 28 | using std::vector; 29 | using std::pair; 30 | using std::string; 31 | 32 | namespace xVerilog { 33 | 34 | /* 35 | */ 36 | class RemoveAllocaPass : public ModulePass { 37 | 38 | public: 39 | /// needed by LLVM 40 | static char ID; 41 | /** 42 | * @brief C'tor in LLVM style 43 | */ 44 | RemoveAllocaPass() : ModulePass((intptr_t)&ID) {} 45 | 46 | /** 47 | * @param AU llvm analysis usage internal object 48 | */ 49 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 50 | //AU.setPreservesCFG(); 51 | } 52 | 53 | virtual bool runOnModule(Module &M); 54 | }; // class 55 | 56 | 57 | 58 | } //end of namespace 59 | #endif // h guard 60 | -------------------------------------------------------------------------------- /PrepareSyn/subscriptDetect.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "llvm/Pass.h" 3 | #include "llvm/Function.h" 4 | #include "llvm/Instructions.h" 5 | #include "llvm/Constants.h" 6 | #include "llvm/ADT/StringExtras.h" 7 | #include "llvm/Support/Streams.h" 8 | #include "llvm/Module.h" 9 | #include "llvm/ADT/Statistic.h" 10 | #include "llvm/ADT/SmallVector.h" 11 | #include "llvm/Support/CFG.h" 12 | #include "llvm/Analysis/FindUsedTypes.h" 13 | #include "llvm/DerivedTypes.h" 14 | #include "llvm/Support/InstIterator.h" 15 | 16 | #include 17 | #include 18 | 19 | #include "../utils.h" 20 | #include "subscriptDetect.h" 21 | 22 | namespace xVerilog { 23 | 24 | void subscriptDetect::incrementAccessIndex(Value* inst, int offset) { 25 | Value* exp; 26 | Value* ld = isLoadSubscript(inst); 27 | Value* st = isStoreSubscript(inst); 28 | exp = (ld? ld : (st? st: NULL )); 29 | assert(exp && "Inst is nither Load or Store array subscript"); 30 | GetElementPtrInst *ptr = dyn_cast(exp); 31 | assert(ptr && "ptr is not of GetElementPtrInst type"); 32 | // Pointer to the value that the GetElementPtrInst uses as index of the array 33 | Value* index = ptr->getOperand(1); 34 | cerr<<"DBG: working on index"<<*index; 35 | 36 | // In this case, change the 'ADD' instruction to reflect the offset 37 | if (BinaryOperator* bin = dyn_cast(index)) { 38 | unsigned int bitWidth = cast(index->getType())->getBitWidth(); 39 | 40 | // if this index is subtracted then we need to negate it first. A[i-(constant+offset)]; 41 | if (bin->getOpcode() == Instruction::Sub) { 42 | offset=-offset; 43 | } 44 | 45 | if (bin->getOpcode() == Instruction::Add || bin->getOpcode() == Instruction::Sub) { 46 | for (int param_num=0; param_num<2;param_num++) { 47 | if (ConstantInt *con = dyn_cast(bin->getOperand(param_num))) { 48 | unsigned int current_off = con->getValue().getZExtValue(); 49 | // create a new constant 50 | ConstantInt *ncon = ConstantInt::get(APInt(bitWidth, offset + current_off)); 51 | bin->setOperand(param_num,ncon); 52 | } 53 | } 54 | } else { 55 | // we can't modify an existing node. Create a new add. 56 | addOffsetToGetElementPtr(ptr,offset); 57 | } 58 | 59 | } else if (isInductionVariable(index)) { 60 | // Else, we add an 'ADD' instruction for the PHI variable 61 | addOffsetToGetElementPtr(ptr,offset); 62 | } else assert(0 && "unknown type of index for array"); 63 | 64 | 65 | } 66 | 67 | void subscriptDetect::addOffsetToGetElementPtr(Value *inst, int offset) { 68 | GetElementPtrInst* ptr = dyn_cast(inst); 69 | assert(ptr && "inst is not of GetElementPtrInst type"); 70 | Value* index = ptr->getOperand(1); 71 | // what's the bitwidth of our index? 72 | unsigned int bitWidth = cast(index->getType())->getBitWidth(); 73 | // New add instruction, place it before the GetElementPtrInst 74 | BinaryOperator* newIndex = BinaryOperator::Create(Instruction::Add, 75 | ConstantInt::get(APInt(bitWidth, offset)) , index, "i_offset", ptr); 76 | // Tell GetElementPtrInst to use it instead of the normal PHI 77 | ptr->setOperand(1,newIndex); 78 | } 79 | 80 | bool subscriptDetect::isInductionVariable(Value *inst) { 81 | return ( m_inductionVariables.find(inst) != m_inductionVariables.end() ); 82 | } 83 | 84 | bool subscriptDetect::isModifiedInductionVariable(Value *inst) { 85 | if (BinaryOperator *calc = dyn_cast(inst)) { 86 | Value *v0 = (calc->getOperand(0)); 87 | Value *v1 = (calc->getOperand(1)); 88 | if ( isInductionVariable(v0) || isInductionVariable(v1)) { 89 | return true; 90 | } 91 | } 92 | return false; 93 | } 94 | 95 | Value* subscriptDetect::isAddressCalculation(Value *inst) { 96 | if (GetElementPtrInst *ptr = dyn_cast(inst)) { 97 | Value *v = (ptr->getOperand(1)); 98 | if (isModifiedInductionVariable(v) || isInductionVariable(v)) { 99 | return ptr; 100 | } 101 | } 102 | return NULL; 103 | } 104 | 105 | Value* subscriptDetect::isLoadSubscript(Value *inst) { 106 | if (LoadInst *ptr = dyn_cast(inst)) { 107 | Value *v = ptr->getOperand(0); 108 | return isAddressCalculation(v); 109 | } 110 | return NULL; 111 | } 112 | 113 | Value* subscriptDetect::isStoreSubscript(Value *inst) { 114 | if (StoreInst *ptr = dyn_cast(inst)) { 115 | Value *v = ptr->getOperand(1); 116 | return isAddressCalculation(v); 117 | } 118 | return NULL; 119 | } 120 | 121 | bool subscriptDetect::runOnFunction(Function &F) { 122 | LoopInfo *LInfo = &getAnalysis(); 123 | 124 | // for each BB, find it's loop 125 | for (Function::const_iterator I = F.begin(), E = F.end(); I!=E; ++I) { 126 | if (Loop *L = LInfo->getLoopFor(I)) { 127 | PHINode* inductionVar = L->getCanonicalInductionVariable(); 128 | if (inductionVar) { 129 | m_inductionVariables.insert(inductionVar); 130 | } 131 | } 132 | } 133 | 134 | // F is a pointer to a Function instance 135 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 136 | Instruction *inst = &*i; 137 | if (isStoreSubscript(inst)) { 138 | cerr<<"Found Store "<<*inst; 139 | m_StoreSubscripts.insert(inst); 140 | } else if (isLoadSubscript(inst)) { 141 | cerr<<"Found Load "<<*inst; 142 | m_LoadSubscripts.insert(inst); 143 | } 144 | } 145 | 146 | return false; 147 | } 148 | 149 | char subscriptDetect::ID = 0; 150 | RegisterPass ADXX("detect_arrays", "Detect arrays in the code"); 151 | 152 | } //namespace 153 | 154 | 155 | -------------------------------------------------------------------------------- /PrepareSyn/subscriptDetect.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_ARRAY_DETECTION_PASS_H 3 | #define LLVM_ARRAY_DETECTION_PASS_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/Analysis/LoopInfo.h" 16 | #include "llvm/DerivedTypes.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | using namespace llvm; 26 | 27 | using std::set; 28 | using std::map; 29 | using std::vector; 30 | using std::pair; 31 | using std::string; 32 | 33 | namespace xVerilog { 34 | 35 | /* 36 | * A pass for detecting different array accesses in the code 37 | */ 38 | class subscriptDetect: public FunctionPass { 39 | 40 | public: 41 | /// needed by LLVM 42 | static char ID; 43 | /** 44 | * @brief C'tor in LLVM style 45 | */ 46 | subscriptDetect() : FunctionPass((intptr_t)&ID) {} 47 | 48 | /** 49 | * @brief Requires LoopInfo analysis and tells llvm that 50 | * we change nothing 51 | * 52 | * @param AU llvm analysis usage internal object 53 | */ 54 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 55 | AU.addRequired(); 56 | AU.addPreserved(); 57 | AU.setPreservesAll(); 58 | } 59 | 60 | virtual bool runOnFunction(Function &F); 61 | 62 | /** 63 | * @brief finds all array references in the function 64 | * 65 | * @param BB 66 | * 67 | * @return vector of instructions which load the pointer to the array 68 | */ 69 | 70 | static vector findAllArrayReferences(Function *F); 71 | 72 | private: 73 | /** 74 | * @brief This will increment the index of the array access. 75 | * For example, It will turn A[i+3] to A[i+5] (for offset = 2). 76 | * 77 | * @param inst the LoadInst/StoreInst of the subscript 78 | * @param offset how much to increment/decrement 79 | */ 80 | void incrementAccessIndex(Value* inst, int offset); 81 | /** 82 | * @brief Tests if this value is an induction variable 83 | * 84 | * @param inst The param we want to check. 85 | * 86 | * @return True if this is an induction variable 87 | */ 88 | bool isInductionVariable(Value *inst); 89 | /** 90 | * @brief Tests if this value is an index which depends on an induction variable 91 | * using a binary operand. For example, [i + 2] will return true because i is indvar and 92 | * we modify it with the binary operation add. 93 | * 94 | * @param inst The param we want to check. 95 | * 96 | * @return True if this is indeed a modified induction variable. 97 | */ 98 | bool isModifiedInductionVariable(Value *inst); 99 | /** 100 | * @brief Tests if this value is a 'getelementptr' instruction which returns 101 | * an address which is obtained via induction pointer. 102 | * 103 | * @param inst The value we want to evaluate 104 | * 105 | * @return pointer to subscript variable if this instruction 106 | * returns the address of a getelementptr. Else, NULL. 107 | */ 108 | Value* isAddressCalculation(Value *inst); 109 | /** 110 | * @brief Tests if this LoadInst loads a value from an array. 111 | * 112 | * @param inst The param we want to check. 113 | * 114 | * @return pointer to subscript variable if this is a subscript, Else NULL. 115 | */ 116 | Value* isLoadSubscript(Value *inst); 117 | /** 118 | * @brief Tests if this StoreInst stores a value to an array. 119 | * 120 | * @param inst The param we want to check. 121 | * 122 | * @return pointer to subscript variable if this is a subscript, Else, NULL. 123 | */ 124 | Value* isStoreSubscript(Value *inst); 125 | /** 126 | * @brief Adds an 'Add' Instruction to the getElementPtr node 127 | * so that it accesses the same expression as before, just 128 | * with an offset. This modifies the node and replaces the 129 | * index parameter with an Add node that uses the previous 130 | * expression plus a constant which reflects the offset. 131 | * 132 | * @param inst The GetElementPtrInst we want to modify 133 | * @param offset The offset we want to add. May be negative. 134 | */ 135 | void addOffsetToGetElementPtr(Value *inst, int offset); 136 | 137 | 138 | /// A storage of the local instruction variables 139 | // It hold phi nodes of induction variables (i in for i loops) 140 | set m_inductionVariables; 141 | 142 | /// At the end of this pass, pointers to arrays are stored 143 | // in this set 144 | set m_LoadSubscripts; 145 | set m_StoreSubscripts; 146 | 147 | }; // class 148 | 149 | 150 | 151 | } //end of namespace 152 | #endif // h guard 153 | -------------------------------------------------------------------------------- /PrepareSyn/subscripts.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "llvm/Pass.h" 3 | #include "llvm/Function.h" 4 | #include "llvm/Instructions.h" 5 | #include "llvm/Constants.h" 6 | #include "llvm/ADT/StringExtras.h" 7 | #include "llvm/Support/Streams.h" 8 | #include "llvm/Module.h" 9 | #include "llvm/ADT/Statistic.h" 10 | #include "llvm/ADT/SmallVector.h" 11 | #include "llvm/Support/CFG.h" 12 | #include "llvm/Analysis/FindUsedTypes.h" 13 | #include "llvm/DerivedTypes.h" 14 | #include "llvm/Support/InstIterator.h" 15 | 16 | #include 17 | #include 18 | 19 | #include "../utils.h" 20 | #include "subscripts.h" 21 | 22 | namespace xVerilog { 23 | 24 | void subscripts::incrementAccessIndex(Value* inst, int offset) { 25 | Value* exp; 26 | Value* ld = isLoadSubscript(inst); 27 | Value* st = isStoreSubscript(inst); 28 | exp = (ld? ld : (st? st: NULL )); 29 | if (NULL == exp) cerr<<"offset:"<(exp); 32 | assert(ptr && "ptr is not of GetElementPtrInst type"); 33 | // Pointer to the value that the GetElementPtrInst uses as index of the array 34 | Value* index = ptr->getOperand(1); 35 | 36 | // In this case, change the 'ADD' instruction to reflect the offset 37 | if (BinaryOperator* bin = dyn_cast(index)) { 38 | unsigned int bitWidth = cast(index->getType())->getBitWidth(); 39 | 40 | // if this index is subtracted then we need to negate it first. A[i-(constant+offset)]; 41 | if (bin->getOpcode() == Instruction::Sub) { 42 | offset=-offset; 43 | } 44 | 45 | if (bin->getOpcode() == Instruction::Add || bin->getOpcode() == Instruction::Sub) { 46 | for (int param_num=0; param_num<2;param_num++) { 47 | if (ConstantInt *con = dyn_cast(bin->getOperand(param_num))) { 48 | unsigned int current_off = con->getValue().getZExtValue(); 49 | // create a new constant 50 | ConstantInt *ncon = ConstantInt::get(APInt(bitWidth, offset + current_off)); 51 | bin->setOperand(param_num,ncon); 52 | } 53 | } 54 | } else { 55 | // we can't modify an existing node. Create a new add. 56 | addOffsetToGetElementPtr(ptr,offset); 57 | } 58 | 59 | } else if (isInductionVariable(index)) { 60 | // Else, we add an 'ADD' instruction for the PHI variable 61 | addOffsetToGetElementPtr(ptr,offset); 62 | } else assert(0 && "unknown type of index for array"); 63 | 64 | 65 | } 66 | 67 | 68 | bool subscripts::isUsedByInductionVariable(Instruction* inst) { 69 | // get the IV 70 | Instruction *iv = getInductionVar(); 71 | // search 'use' chain and see if iv is one of them 72 | if (std::find(inst->use_begin(), inst->use_end(), iv) != inst->use_end()) { 73 | return true; 74 | } 75 | return false; 76 | } 77 | 78 | 79 | void subscripts::addOffsetToGetElementPtr(Value *inst, int offset) { 80 | GetElementPtrInst* ptr = dyn_cast(inst); 81 | assert(ptr && "inst is not of GetElementPtrInst type"); 82 | Value* index = ptr->getOperand(1); 83 | // what's the bitwidth of our index? 84 | unsigned int bitWidth = cast(index->getType())->getBitWidth(); 85 | // New add instruction, place it before the GetElementPtrInst 86 | BinaryOperator* newIndex = BinaryOperator::Create(Instruction::Add, 87 | ConstantInt::get(APInt(bitWidth, offset)) , index, "i_offset", ptr); 88 | // Tell GetElementPtrInst to use it instead of the normal PHI 89 | ptr->setOperand(1,newIndex); 90 | } 91 | 92 | bool subscripts::isInductionVariable(Value *inst) { 93 | return (m_inductionVariables.find(inst) != m_inductionVariables.end() ); 94 | } 95 | 96 | bool subscripts::isModifiedInductionVariable(Value *inst) { 97 | if (BinaryOperator *calc = dyn_cast(inst)) { 98 | Value *v0 = (calc->getOperand(0)); 99 | Value *v1 = (calc->getOperand(1)); 100 | if ( isInductionVariable(v0) || isInductionVariable(v1)) { 101 | return true; 102 | } 103 | } 104 | return false; 105 | } 106 | 107 | Value* subscripts::isAddressCalculation(Value *inst) { 108 | if (GetElementPtrInst *ptr = dyn_cast(inst)) { 109 | Value *v = (ptr->getOperand(1)); 110 | if (isModifiedInductionVariable(v) || isInductionVariable(v)) { 111 | return ptr; 112 | } 113 | } 114 | return NULL; 115 | } 116 | 117 | Value* subscripts::isLoadSubscript(Value *inst) { 118 | if (LoadInst *ptr = dyn_cast(inst)) { 119 | Value *v = ptr->getOperand(0); 120 | return isAddressCalculation(v); 121 | } 122 | return NULL; 123 | } 124 | 125 | Value* subscripts::isStoreSubscript(Value *inst) { 126 | if (StoreInst *ptr = dyn_cast(inst)) { 127 | Value *v = ptr->getOperand(1); 128 | return isAddressCalculation(v); 129 | } 130 | return NULL; 131 | } 132 | 133 | void subscripts::detectInductionVariables(Loop* loop) { 134 | // for each BB, find it's loop 135 | for (Loop::block_iterator I = loop->block_begin(), E = loop->block_end(); I!=E; ++I) { 136 | //TODO: WTF ? 137 | PHINode* inductionVar = loop->getCanonicalInductionVariable(); 138 | if (inductionVar) { 139 | // Collect all induction variables in here 140 | m_inductionVariables.insert(inductionVar); 141 | } 142 | } 143 | } 144 | 145 | void subscripts::detectSubscripts(BasicBlock* bb) { 146 | for (BasicBlock::iterator i = (bb)->begin(); i != (bb)->end(); ++i) { 147 | Instruction *inst = i; 148 | if (isStoreSubscript(inst)) { 149 | //cerr<<"Found Store "<<*inst; 150 | m_StoreSubscripts.insert(inst); 151 | } else if (isLoadSubscript(inst)) { 152 | //cerr<<"Found Load "<<*inst; 153 | m_LoadSubscripts.insert(inst); 154 | } 155 | } 156 | } 157 | 158 | void subscripts::detectSubscripts(Loop* loop) { 159 | // detect A[i] accesses over all basic blocks in this loop 160 | for (Loop::block_iterator b = loop->block_begin(); b != loop->block_end(); ++b) { 161 | detectSubscripts(*b); 162 | } 163 | } 164 | 165 | void subscripts::normalizeSubscripts() { 166 | // by incrementing all we force them to be in the form A[i+0] 167 | incrementAllSubscripts(0); 168 | } 169 | 170 | void subscripts::incrementIfSubscript(Value* inst, int offset) { 171 | 172 | if (m_LoadSubscripts.end() != m_LoadSubscripts.find(inst) || 173 | m_StoreSubscripts.end() != m_StoreSubscripts.find(inst)) { 174 | incrementAccessIndex(inst, offset); 175 | } 176 | 177 | } 178 | 179 | void subscripts::incrementAllSubscripts(int offset) { 180 | for(set::iterator it = m_LoadSubscripts.begin(); it!= m_LoadSubscripts.end(); ++it) { 181 | incrementAccessIndex(*it,offset); 182 | } 183 | for(set::iterator it = m_StoreSubscripts.begin(); it!= m_StoreSubscripts.end(); ++it) { 184 | incrementAccessIndex(*it,offset); 185 | } 186 | } 187 | 188 | Instruction* subscripts::incrementValue(Value* val, int offset, Instruction* insert) { 189 | if (offset == 0 && dyn_cast(val)) { 190 | // If we do not need to change the offset and we know 191 | // that val is an instruction 192 | return dyn_cast(val); 193 | } 194 | unsigned int bitWidth = cast(val->getType())->getBitWidth(); 195 | ConstantInt *ncon = ConstantInt::get(APInt(bitWidth, offset)); 196 | if (insert) { 197 | return BinaryOperator::Create(Instruction::Add, ncon, val, "incrementVal",insert); 198 | } else { 199 | return BinaryOperator::Create(Instruction::Add, ncon, val, "incrementVal"); 200 | } 201 | } 202 | 203 | } //namespace 204 | 205 | 206 | -------------------------------------------------------------------------------- /PrepareSyn/subscripts.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_SUBSCRIPTS_HELPER_H 3 | #define LLVM_SUBSCRIPTS_HELPER_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/Analysis/LoopInfo.h" 16 | #include "llvm/DerivedTypes.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | using namespace llvm; 26 | 27 | using std::set; 28 | using std::map; 29 | using std::vector; 30 | using std::pair; 31 | using std::string; 32 | 33 | namespace xVerilog { 34 | 35 | /* 36 | * A pass for detecting different array accesses in the code 37 | */ 38 | class subscripts { 39 | public: 40 | /** 41 | * @brief C'tor, detects all load/stores to arrays 42 | * which are inside a loop 43 | */ 44 | subscripts(Loop* myLoop) { 45 | detectInductionVariables(myLoop); 46 | detectSubscripts(myLoop); 47 | } 48 | 49 | subscripts(BasicBlock *bb, Instruction* inductionVar) { 50 | m_inductionVariables.insert(inductionVar); 51 | detectSubscripts(bb); 52 | } 53 | /** 54 | * @brief Tests if this LoadInst loads a value from an array. 55 | * 56 | * @param inst The param we want to check. 57 | * 58 | * @return pointer to subscript variable if this is a subscript, Else NULL. 59 | */ 60 | Value* isLoadSubscript(Value *inst); 61 | /** 62 | * @brief Tests if this StoreInst stores a value to an array. 63 | * 64 | * @param inst The param we want to check. 65 | * 66 | * @return pointer to subscript variable if this is a subscript, Else, NULL. 67 | */ 68 | Value* isStoreSubscript(Value *inst); 69 | /** 70 | * @brief Turn all A[i] subscripts to the form of A[i+0] form. 71 | * This will allow us to easily change it to A[i+c] for the modulo 72 | * scheduler 73 | */ 74 | void normalizeSubscripts(); 75 | 76 | /** 77 | * @brief If this is a subscript (array access) then increment 78 | * the offset of the index by 'offset'. Ex: A[i] becomes A[i+3] 79 | * 80 | * @param inst the possible induction variable 81 | * @param offset the offset to increment by. 82 | */ 83 | void incrementIfSubscript(Value* inst, int offset); 84 | /** 85 | * @brief Increment the index of all subscripts (A[i+2] -> A[i+2+offset]) 86 | * 87 | * @param offset 88 | */ 89 | void incrementAllSubscripts(int offset); 90 | /** 91 | * @brief return the induction variable 92 | */ 93 | Instruction* getInductionVar() { 94 | if (Instruction *ind = dyn_cast(*m_inductionVariables.begin())) return ind; 95 | assert(0 && "No instruction variable"); 96 | return NULL; 97 | } 98 | 99 | /** 100 | * @brief A helper method for incrementing Values. This creates 101 | * a new value. Only works for integers. It does not insert the command 102 | * to anywhere. 103 | * 104 | * @param val The value to change Ex: A 105 | * @param offset how much to increment. Ex: 5 106 | * @param inst if this is non null, insert the instruction here 107 | * @param return new result. Ex: A+5 108 | */ 109 | static Instruction* incrementValue(Value* val, int offset, Instruction* insert=0); 110 | 111 | /** 112 | * @brief Returns true if the induction variable directly depends on this instruction. 113 | * For example in the case of (i := i+1) 114 | * 115 | * @param inst the instruction to test 116 | * 117 | * @return true if IV directly depends on inst 118 | */ 119 | bool isUsedByInductionVariable(Instruction* inst); 120 | 121 | private: 122 | /** 123 | * @brief Adds an 'Add' Instruction to the getElementPtr node 124 | * so that it accesses the same expression as before, just 125 | * with an offset. This modifies the node and replaces the 126 | * index parameter with an Add node that uses the previous 127 | * expression plus a constant which reflects the offset. 128 | * 129 | * @param inst The GetElementPtrInst we want to modify 130 | * @param offset The offset we want to add. May be negative. 131 | */ 132 | void addOffsetToGetElementPtr(Value *inst, int offset=0); 133 | /** 134 | * @brief Scans the loop and finds all of the Load/Store 135 | * to array inside a loop 136 | */ 137 | void detectSubscripts(Loop* loop); 138 | /** 139 | * @brief Scans the BB and finds all of the Load/Store 140 | * to array inside a loop 141 | */ 142 | void detectSubscripts(BasicBlock* bb); 143 | /** 144 | * @brief This will increment the index of the array access. 145 | * For example, It will turn A[i+3] to A[i+5] (for offset = 2). 146 | * 147 | * @param inst the LoadInst/StoreInst of the subscript 148 | * @param offset how much to increment/decrement 149 | */ 150 | void incrementAccessIndex(Value* inst, int offset); 151 | /* 152 | * @brief Detect all induction variables in this loop and insert them to the set 153 | */ 154 | void detectInductionVariables(Loop* loop); 155 | /** 156 | * @brief Tests if this value is an induction variable 157 | * 158 | * @param inst The param we want to check. 159 | * 160 | * @return True if this is an induction variable 161 | */ 162 | bool isInductionVariable(Value *inst); 163 | /** 164 | * @brief Tests if this value is an index which depends on an induction variable 165 | * using a binary operand. For example, [i + 2] will return true because i is indvar and 166 | * we modify it with the binary operation add. 167 | * 168 | * @param inst The param we want to check. 169 | * 170 | * @return True if this is indeed a modified induction variable. 171 | */ 172 | bool isModifiedInductionVariable(Value *inst); 173 | /** 174 | * @brief Tests if this value is a 'getelementptr' instruction which returns 175 | * an address which is obtained via induction pointer. 176 | * 177 | * @param inst The value we want to evaluate 178 | * 179 | * @return pointer to subscript variable if this instruction 180 | * returns the address of a getelementptr. Else, NULL. 181 | */ 182 | Value* isAddressCalculation(Value *inst); 183 | 184 | /// A storage of the local instruction variables 185 | // It hold phi nodes of induction variables (i in for i loops) 186 | set m_inductionVariables; 187 | 188 | /// At the end of this pass, pointers to arrays are stored 189 | // in this set 190 | set m_LoadSubscripts; 191 | set m_StoreSubscripts; 192 | 193 | }; // class 194 | 195 | 196 | 197 | } //end of namespace 198 | #endif // h guard 199 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a fork of the code from www.c-to-verilog.com 2 | 3 | The original code was written by Nadav Rotem. 4 | 5 | Since the original code was not released under any form of source code control, and has not advanced for some time, I moved it to a public GIT repository in order to advance it further. 6 | Near term goals are to update the code to the latest LLVM relase (currently the code requires LLVM 2.5). 7 | 8 | This code is licensed under the GPL v3 license, according to the terms in www.c-to-verilog.com 9 | 10 | In order to compile this code, please install gcc 4.2.4 (different versions may work, but I've tried only with 4.2.4) 11 | 12 | Installing and compiling the code (This has been tried on 64-bit CentOS 7.1): 13 | 14 | **You might require the following packages if you don't already have those:** 15 | 16 | sudo yum install git bison flex glibc-devel.i686 gcc-g++ cmake 17 | 18 | **Here we start** 19 | 20 | Get source code 21 | 22 | cd $HOME 23 | wget http://www.llvm.org/releases/2.5/llvm-2.5.tar.gz 24 | wget http://llvm.org/releases/2.5/llvm-gcc-4.2-2.5.source.tar.gz 25 | 26 | Extract source code 27 | 28 | tar xvfz llvm-2.5.tar.gz 29 | cd llvm-2.5/lib/Target 30 | 31 | Clone the ctoverilog repository. Notice the target directory name. This is important! 32 | 33 | git clone https://github.com/udif/ctoverilog.git Verilog 34 | cd $HOME/llvm-2.5 35 | 36 | Prepare default configuration 37 | 38 | ./configure 39 | 40 | Fix the configuration to add the Verilog directory 41 | 42 | sed -i -e 's/CppBackend/CppBackend Verilog/g' Makefile.config 43 | sed -i '/Sparc/a\ Verilog' CMakeLists.txt 44 | 45 | Now build LLVM. Notice we rebuild twice. The first make fails on lcc link problems. Rerunning ./configure and make will fix that. This is workaround until I figure out the root cause for this problem. 46 | 47 | make ; ./configure ; make 48 | 49 | Follow instructions from llvm-gcc4.2-2.5.source/README.LLVM to install the gcc front end to LLVM: 50 | 51 | cd $HOME 52 | wget http://llvm.org/releases/2.5/llvm-gcc-4.2-2.5.source.tar.gz 53 | mkdir llvm-gcc 54 | cd llvm-gcc 55 | tar xvfz ../llvm-gcc-4.2-2.5.source.tar.gz 56 | mkdir obj install 57 | cd obj 58 | LLVMOBJDIR=~/llvm-2.5 59 | BUILDOPTIONS=LLVM_VERSION_INFO=2.5 60 | ../llvm-gcc4.2-2.5.source/configure --prefix=`pwd`/../install --program-prefix=llvm- --enable-llvm=$LLVMOBJDIR --enable-languages=c,c++ --disable-multilib 61 | make $BUILDOPTIONS 62 | make install 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /Synthesis/Makefile: -------------------------------------------------------------------------------- 1 | ##===- lib/Target/VBackend/Makefile ------------------------*- Makefile -*-===## 2 | # 3 | # The LLVM Compiler Infrastructure 4 | # 5 | # This file was developed by the LLVM research group and is distributed under 6 | # the University of Illinois Open Source License. See LICENSE.TXT for details. 7 | # 8 | ##===----------------------------------------------------------------------===## 9 | 10 | LEVEL = ../../../.. 11 | LIBRARYNAME = LLVMSynthesis 12 | TARGET=Verilog 13 | LOADABLE_MODULE = 1 14 | BUILT_SOURCES=../params.cpp 15 | include $(LEVEL)/Makefile.common 16 | 17 | 18 | CompileCommonOpts += -Wno-format 19 | #CXX=icc 20 | #CC=icc 21 | # DO NOT DELETE 22 | 23 | abstractHWOpcode.o: abstractHWOpcode.h ../params.h globalVarsRegistry.h 24 | designScorer.o: designScorer.h listScheduler.h ../utils.h ../params.h 25 | designScorer.o: abstractHWOpcode.h globalVarsRegistry.h 26 | globalVarsRegistry.o: globalVarsRegistry.h 27 | instPriority.o: instPriority.h ../utils.h abstractHWOpcode.h ../params.h 28 | instPriority.o: globalVarsRegistry.h 29 | intrinsics.o: intrinsics.h 30 | listScheduler.o: listScheduler.h ../utils.h ../params.h abstractHWOpcode.h 31 | listScheduler.o: globalVarsRegistry.h instPriority.h 32 | Opcodes.o: Opcodes.h ../params.h globalVarsRegistry.h 33 | VBackend.o: VTargetMachine.h listScheduler.h ../utils.h ../params.h 34 | VBackend.o: abstractHWOpcode.h globalVarsRegistry.h verilogLang.h 35 | VBackend.o: designScorer.h 36 | verilogLang.o: verilogLang.h listScheduler.h ../utils.h ../params.h 37 | verilogLang.o: abstractHWOpcode.h globalVarsRegistry.h intrinsics.h 38 | -------------------------------------------------------------------------------- /Synthesis/Opcodes.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "Opcodes.h" 3 | 4 | namespace xVerilog{ 5 | 6 | DelayInst::DelayInst( 7 | Value *S, const Type *Ty, const std::string &Name, Instruction *InsertBefore 8 | ) : CastInst(Ty, ZExt, S, Name, InsertBefore) { 9 | } 10 | 11 | DelayInst::DelayInst( 12 | Value *S, const Type *Ty, const std::string &Name, BasicBlock *InsertAtEnd 13 | ) : CastInst(Ty, ZExt, S, Name, InsertAtEnd) { 14 | } 15 | 16 | 17 | InInst::InInst(const InInst &In): 18 | Instruction(In.getType(),0,0,0) { 19 | } 20 | 21 | InInst::InInst(const Type *Ty, Value *value, ExternamModule *where): 22 | Instruction(Ty,OtherOpsEnd,0,0), m_type(Ty), m_toSave(value), m_extern(where){ 23 | } 24 | 25 | InInst* InInst::clone() const { 26 | assert(0 && "Cannot clone EOL");abort(); 27 | return 0; 28 | } 29 | 30 | CastInst *DelayInst::clone() const { return new DelayInst(*this); } 31 | 32 | } // namespace 33 | -------------------------------------------------------------------------------- /Synthesis/Opcodes.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_OPCODE_OP_H 3 | #define LLVM_OPCODE_OP_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/DerivedTypes.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "../params.h" 25 | #include "globalVarsRegistry.h" 26 | using namespace llvm; 27 | 28 | using std::set; 29 | using std::map; 30 | using std::vector; 31 | using std::pair; 32 | using std::string; 33 | 34 | namespace xVerilog { 35 | 36 | class ExternamModule; 37 | 38 | /// @brief This class represents a static delay. 39 | class DelayInst : public CastInst { 40 | /// @brief Private copy constructor 41 | DelayInst(const DelayInst &CI) 42 | : CastInst(CI.getType(), ZExt, CI.getOperand(0)) { 43 | } 44 | public: 45 | /// @brief Constructor with insert-before-instruction semantics 46 | DelayInst( 47 | Value *S, ///< The value to be zero extended 48 | const Type *Ty, ///< The type to zero extend to 49 | const std::string &Name = "", ///< A name for the new instruction 50 | Instruction *InsertBefore = 0 ///< Where to insert the new instruction 51 | ); 52 | 53 | /// @brief Constructor with insert-at-end semantics. 54 | DelayInst( 55 | Value *S, ///< The value to be zero extended 56 | const Type *Ty, ///< The type to zero extend to 57 | const std::string &Name, ///< A name for the new instruction 58 | BasicBlock *InsertAtEnd ///< The block to insert the instruction into 59 | ); 60 | 61 | /// @brief Clone an identical DelayInst 62 | virtual CastInst *clone() const; 63 | 64 | /// @brief Methods for support type inquiry through isa, cast, and dyn_cast: 65 | static inline bool classof(const DelayInst *) { return true; } 66 | static inline bool classof(const Instruction *I) { 67 | // TODO: fixme 68 | return I->getOpcode() == ZExt; 69 | } 70 | static inline bool classof(const Value *V) { 71 | return isa(V) && classof(cast(V)); 72 | } 73 | }; 74 | 75 | 76 | 77 | 78 | class InInst: public Instruction { 79 | public: 80 | InInst(const Type *Ty, Value *value, ExternamModule *where); 81 | InInst(const InInst &In); 82 | virtual InInst *clone() const; 83 | 84 | const char *getOpcodeName() const { return "*end-of-list-inst*"; } 85 | const Type* getType() const { return m_type; } 86 | 87 | // Methods for support type inquiry through isa, cast, and dyn_cast... 88 | static inline bool classof(const InInst *) { return true; } 89 | static inline bool classof(const Instruction *I) { 90 | return I->getOpcode() == OtherOpsEnd; 91 | } 92 | static inline bool classof(const Value *V) { 93 | return isa(V) && classof(cast(V)); 94 | } 95 | 96 | 97 | private: 98 | // link to externam module 99 | const Type* m_type; 100 | Value* m_toSave; 101 | ExternamModule* m_extern; 102 | }; // class 103 | 104 | 105 | 106 | } //end of namespace 107 | #endif // h guard 108 | -------------------------------------------------------------------------------- /Synthesis/VBackend.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "VTargetMachine.h" 3 | #include "llvm/CallingConv.h" 4 | #include "llvm/Constants.h" 5 | #include "llvm/DerivedTypes.h" 6 | #include "llvm/Module.h" 7 | #include "llvm/Instructions.h" 8 | //#include "llvm/ParameterAttributes.h" 9 | #include "llvm/Pass.h" 10 | #include "llvm/PassManager.h" 11 | #include "llvm/TypeSymbolTable.h" 12 | #include "llvm/Intrinsics.h" 13 | #include "llvm/IntrinsicInst.h" 14 | #include "llvm/InlineAsm.h" 15 | #include "llvm/Analysis/ConstantsScanner.h" 16 | #include "llvm/Analysis/FindUsedTypes.h" 17 | #include "llvm/Analysis/LoopInfo.h" 18 | #include "llvm/CodeGen/IntrinsicLowering.h" 19 | #include "llvm/Transforms/Scalar.h" 20 | #include "llvm/Target/TargetMachineRegistry.h" 21 | #include "llvm/Target/TargetAsmInfo.h" 22 | #include "llvm/Target/TargetData.h" 23 | #include "llvm/Support/CallSite.h" 24 | #include "llvm/Support/CFG.h" 25 | #include "llvm/Support/GetElementPtrTypeIterator.h" 26 | #include "llvm/Support/InstVisitor.h" 27 | #include "llvm/Support/Mangler.h" 28 | #include "llvm/Support/MathExtras.h" 29 | #include "llvm/ADT/StringExtras.h" 30 | #include "llvm/ADT/STLExtras.h" 31 | #include "llvm/Support/MathExtras.h" 32 | #include "llvm/Config/config.h" 33 | #include 34 | #include 35 | #include "llvm/Support/raw_ostream.h" 36 | 37 | #include 38 | #include "llvm/Transforms/Utils/Cloning.h" 39 | 40 | #include "listScheduler.h" 41 | #include "verilogLang.h" 42 | #include "designScorer.h" 43 | #include "../params.h" 44 | 45 | using namespace llvm; 46 | using std::string; 47 | using std::stringstream; 48 | using llvm::TargetData; //JAWAD 49 | namespace xVerilog { 50 | // Register the target. 51 | static RegisterTarget MXVVE("v", "Verilog backend"); 52 | 53 | /// VWriter - This class is the main chunk of code that converts an LLVM 54 | /// module to a Verilog translation unit. 55 | class VWriter : public FunctionPass { 56 | 57 | public: 58 | static char ID; 59 | VWriter(llvm::raw_ostream &o) 60 | : FunctionPass((intptr_t)&ID),Out(o) {} 61 | 62 | virtual const char *getPassName() const { return "verilog backend"; } 63 | 64 | void getAnalysisUsage(AnalysisUsage &AU) const { 65 | AU.addRequired(); 66 | AU.addPreserved(); 67 | AU.addRequired();//JAWAD 68 | AU.setPreservesAll(); 69 | } 70 | 71 | virtual bool doInitialization(Module &M); 72 | virtual bool doFinalization(Module &M); 73 | 74 | bool runOnFunction(Function &F); 75 | 76 | private: 77 | llvm::raw_ostream &Out; 78 | Mangler *Mang; 79 | }; 80 | 81 | 82 | 83 | char VWriter::ID = 0; 84 | 85 | bool VWriter::runOnFunction(Function &F) { 86 | for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I) { //JAWAD 87 | string argname = I->getName(); 88 | argname = machineResourceConfig::chrsubst(argname,'.','_'); 89 | I->setName (argname); 90 | }; 91 | 92 | //DenseMap ValueMap; 93 | //Function *newFunc = llvm::CloneFunction (&F,ValueMap); 94 | 95 | //std::cerr<<"Converting to verilog this function:\n" <();//JAWAD 98 | verilogLanguage verilogPrinter(F.getParent(),Mang,TD); 99 | 100 | listSchedulerVector lv; 101 | 102 | Out<< "/* This module was generated by c-to-verilog.com\n" 103 | " * THIS SOFTWARE IS PROVIDED BY www.c-to-verilog.com ''AS IS'' AND ANY\n" 104 | " * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n" 105 | " * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n" 106 | " * DISCLAIMED. IN NO EVENT SHALL c-to-verilog.com BE LIABLE FOR ANY\n" 107 | " * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n" 108 | " * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES)\n" 109 | " * \n" 110 | " * Found a bug? email info@c-to-verilog.com \n" 111 | " */\n\n\n"; 112 | 113 | 114 | LoopInfo *LInfo = &getAnalysis(); 115 | designScorer ds(LInfo); 116 | 117 | for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { 118 | listScheduler *ls = new listScheduler(BB,TD); //JAWAD 119 | lv.push_back(ls); 120 | ds.addListScheduler(ls); 121 | } 122 | 123 | map resourceMap = 124 | machineResourceConfig::getResourceTable(); 125 | 126 | unsigned int include_size = resourceMap["include_size"]; 127 | unsigned int include_freq = resourceMap["include_freq"]; 128 | unsigned int include_clocks = resourceMap["include_clocks"]; 129 | float MDF = (float)resourceMap["delay_memport"]; 130 | 131 | float freq = ds.getDesignFrequency(); 132 | float clocks = ds.getDesignClocks(); 133 | float gsize = ds.getDesignSizeInGates(&F); 134 | 135 | if (0==include_freq) freq = 1; 136 | if (0==include_clocks) clocks = 1; 137 | if (0==include_size) gsize = 1; 138 | 139 | cerr<<"\n\n--- Synthesis Report ----\n"; 140 | cerr<<"Estimated circuit delay : " << freq<<"ns ("<<1000/freq<<"Mhz)\n"; 141 | cerr<<"Estimated circuit size : " << gsize<<"\n"; 142 | cerr<<"Calculated loop throughput: " << clocks<<"\n"; 143 | cerr<<"--------------------------\n"; 144 | 145 | Out<<"/* Total Score= |"<< ((clocks*sqrt(clocks))*(freq)*(gsize))/(MDF) <<"| */"; 146 | Out<<"/* freq="<markCharUnacceptable('.'); 194 | globalVarRegistry gvr; 195 | gvr.init(&M); 196 | return true; 197 | } 198 | 199 | } // namespace 200 | 201 | //===----------------------------------------------------------------------===// 202 | // External Interface declaration 203 | //===----------------------------------------------------------------------===// 204 | 205 | bool VTargetMachine::addPassesToEmitWholeFile(PassManager &PM, llvm::raw_ostream &o, 206 | CodeGenFileType FileType, bool Fast) { 207 | if (FileType != TargetMachine::AssemblyFile) return true; 208 | 209 | PM.add(new xVerilog::VWriter(o)); 210 | return false; 211 | } 212 | -------------------------------------------------------------------------------- /Synthesis/VTargetMachine.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef VTARGETMACHINE_H 3 | #define VTARGETMACHINE_H 4 | 5 | #include "llvm/Target/TargetMachine.h" 6 | #include "llvm/Target/TargetData.h" 7 | 8 | namespace llvm { 9 | 10 | struct VTargetMachine : public TargetMachine { 11 | const TargetData DataLayout; // Calculates type size & alignment 12 | 13 | VTargetMachine(const Module &M, const std::string &FS) 14 | : DataLayout(&M) {} 15 | 16 | virtual bool WantsWholeFile() const { return true; } 17 | virtual bool addPassesToEmitWholeFile(PassManager &PM, raw_ostream &Out, 18 | CodeGenFileType FileType, bool Fast); 19 | 20 | // This class always works, but shouldn't be the default in most cases. 21 | static unsigned getModuleMatchQuality(const Module &M) { return 1; } 22 | 23 | virtual const TargetData *getTargetData() const { return &DataLayout; } 24 | }; 25 | 26 | } // End llvm namespace 27 | 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /Synthesis/abstractHWOpcode.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_ABSTRACT_HW_OP_H 3 | #define LLVM_ABSTRACT_HW_OP_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/DerivedTypes.h" 16 | #include "llvm/Target/TargetData.h" //JAWAD 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "../params.h" 26 | #include "globalVarsRegistry.h" 27 | using namespace llvm; 28 | 29 | using std::set; 30 | using std::map; 31 | using std::vector; 32 | using std::pair; 33 | using std::string; 34 | 35 | using llvm::TargetData; //JAWAD 36 | typedef vector InstructionVector; 37 | typedef vector InstructionCycle; 38 | typedef vector InstructionSequence; 39 | 40 | namespace xVerilog { 41 | 42 | /* A class which represents a usage of a hardware module. For example, 43 | * connecting two registers to a multiplier unit. The inputs are the 44 | * two Value classes. You know which hardware unit you are assigned to by 45 | * the hardware unit it is schedueld to. 46 | */ 47 | class assignPartEntry { 48 | public: 49 | assignPartEntry(Value* left, Value* right): 50 | m_left(left),m_right(right){} 51 | 52 | Value* getLeft(){return m_left;} 53 | Value* getRight(){return m_right;} 54 | 55 | /* 56 | * set the unit id and unit name of this assign part. The unit id is 57 | * the id of the execution unit and the name is the name of the unit. 58 | * Also, state name is needed so we can assign it to the right state. 59 | */ 60 | void setUnit(unsigned int unitid, const string& name, 61 | const string& stateName, unsigned int cycle); 62 | 63 | /* 64 | * @return the name of the unit, for example multiply1 65 | */ 66 | string getUnitName(); 67 | 68 | string getUnitType() {return m_unitName;} 69 | 70 | string getState(){return m_state;} 71 | 72 | private: 73 | unsigned int m_unitId; 74 | string m_unitName; 75 | string m_state; 76 | 77 | Value* m_left; 78 | Value* m_right; 79 | }; // class 80 | 81 | typedef std::pair ArrayInfo; 82 | /* 83 | * Represents an original LLVM instruction which is broken down into 84 | * multiple hardware instructions. 85 | */ 86 | class abstractHWOpcode { 87 | public: 88 | /* 89 | * C'tor 90 | * @param inst is the LLVM instruction to be represented in the abstract opcode 91 | * this may modify the bitcode structure. It may add/remove and change the 92 | * dependencies of instructions. 93 | * @param streamNum the number of streams in this opcode. 94 | * There are n streams. 95 | * We define multiple streams so that we can have instructions which use two pipelined 96 | * dependencies such as this one. 97 | * --> time 98 | * resource 1a: ..AB... 99 | * resource 1b: ...AB.. 100 | */ 101 | abstractHWOpcode(Instruction* inst, std::string stateName, unsigned int streamNum = 2,TargetData* TD = NULL); //JAWAD 102 | /* 103 | * A builder function used to define a hardware opcode using LLVM opcodes. 104 | * Adds a cycle of instructions to the opcode. The cycle may be empty from any ops. 105 | * This is used in many pipelined ops where only the first cycle contain assignments 106 | * while the rest of the cycles are simply delay ones. In other words, empty cycles 107 | * at the end of the opcode means that the data is in the pipeline and will be ready 108 | * as soon these cycles pass. 109 | * 110 | */ 111 | void appendInstructionCycle(InstructionCycle ops, unsigned int streamID) { 112 | m_iv[streamID].push_back(ops); 113 | } 114 | /* 115 | * Append an instruction, which is not directly mapped to a uOp 116 | * to a list of instructions which ARE used in the calculation of 117 | * dependencies between abstractHWOpcodes. (in the case of assign aprt) 118 | */ 119 | void appendUsedInstruction(Instruction* inst) {m_usedInst.insert(inst);} 120 | 121 | InstructionCycle cycleAt(unsigned int streamID, unsigned int cycle) { 122 | if (streamID < m_iv.size()) 123 | if (cycle < m_iv[streamID].size()) 124 | return m_iv[streamID][cycle]; 125 | InstructionCycle nop; 126 | return nop; 127 | } 128 | /** 129 | * @return are there any uOp instructions on a stream in a cycle 130 | */ 131 | bool emptyAt(unsigned int streamID, unsigned int cycle) { 132 | return (0 == cycleAt(streamID, cycle).size()); 133 | } 134 | /* 135 | * returns the number of cycles that this instruction take. The 136 | * length of the longest stream. 137 | */ 138 | unsigned int getLength(); 139 | /* 140 | * returns the number of cycles that this instruction take. 141 | */ 142 | unsigned int getLength(unsigned int streamID) {return m_iv[streamID].size();} 143 | /* 144 | * Returns the hardware instructions at a given clock. 145 | */ 146 | InstructionCycle getInstructionForCycle(int cycle); 147 | /* 148 | * Declare that this opcode depends on the result of another opcode 149 | */ 150 | void addDependency(abstractHWOpcode* dep); 151 | /* 152 | * True if this opcode depend on the opcode 'dep'. 153 | */ 154 | bool isDepends(abstractHWOpcode* dep); 155 | /* 156 | * @returns the index of the cycle which is good to schedule. 157 | * scans all of the dependencies and tells the first instruction which does 158 | * not depend on any of the other instruction. 159 | */ 160 | unsigned int getFirstSchedulableSlot(); 161 | /* 162 | * Searches for the LLVM instruction 'inst' in this instruction group 163 | * This is used for establishing the dependencies between the opcodes. 164 | */ 165 | Instruction* hasInstruction(Instruction *inst); 166 | /* 167 | * 168 | * Searches for the ANY of the instructions in this instruction group 169 | */ 170 | Instruction* hasInstruction(std::vector &insts); 171 | /* 172 | *@return the name of this instruction. 173 | * For example: 'memport' if this is a memory access. 174 | */ 175 | std::string getName() { return m_opcodeName;} 176 | /* 177 | * @return this hwop as a string 178 | */ 179 | string toString(); 180 | /* 181 | * Add a dependency of this opcode on 'hwop' if it has an opcode 182 | * which is a dependency of our instructions. 183 | */ 184 | void addDependencyIfDepends(abstractHWOpcode *hwop); 185 | /* 186 | * Sets the starting cycle of this opcode in the scheduling table. 187 | * The list scheduler uses this to place the opcode in the instruction table. 188 | * This is used to clculate the next available slot for the next opcode. 189 | * It also records to which instance of the execution units it is scheduled 190 | */ 191 | void place(unsigned int cycle,unsigned int unitid); 192 | /* 193 | * returns the place where this opcode was scheduled. see place() 194 | */ 195 | unsigned int getPlace() {return m_place;} 196 | /* 197 | * Returns the first free cycle after the ending offset of this 198 | * opcode in the shcheduling table. 199 | */ 200 | unsigned int getFirstAfter() { return m_place + getLength(); } 201 | /* 202 | * @returns the assign part of the opcode, NULL if not present 203 | */ 204 | assignPartEntry* getAssignPart() {return m_assignPart;} 205 | /** 206 | * @param inst the parameter to check 207 | * 208 | * @return a static function to see if this operation can be implemented in 209 | * hardware using wires only (example shl by a constant) 210 | */ 211 | static bool isInstructionOnlyWires(Instruction* inst); 212 | /** 213 | * @brief Is this opcode must come last in BasicBlock ? 214 | * 215 | * @return True if yes 216 | */ 217 | bool isMustBeLastOpcode() { return m_mustBeLast; } 218 | 219 | /** 220 | * @brief Finds the width in bits of this element type. May be a pointer, an integer or an array. 221 | * 222 | * @param type Type 223 | * 224 | * @return bit width 225 | */ 226 | static const StructType* isPtrToStructType(const Value* Op); //JAWAD 227 | llvm::TargetData* TD; //JAWAD 228 | private: 229 | /* 230 | * Add a dependency of this opcode on 'hwop' if it has an opcode 231 | * which is a dependency of our instructions. 232 | * 233 | * @param iv looks for dependencies only in the stream iv 234 | */ 235 | void addDependencyIfDepends(abstractHWOpcode *hwop, InstructionSequence &iv); 236 | /* 237 | * Serves the C'tor in creating a binary operation, which uses assign part, 238 | * such as 'mul' or 'div'. Creates the needed uOps and instructions. 239 | */ 240 | void addBinaryInstruction(Instruction* inst, string op, unsigned int delay); 241 | /** 242 | * @brief This method returns all 'incoming' instruction from a BasicBlock 243 | * we use this in order to see which values delay the branch instruction. 244 | * It scans all of the PHI nodes and returns Instructions from All BBs, not 245 | * only this one. 246 | * 247 | * @param bb the BasicBlock we want to scan. 248 | * 249 | * @return A vector of instructions. 250 | */ 251 | static std::vector getAllIncomingValuesFromPHIs(BasicBlock* bb); 252 | /** 253 | * @brief Return all of the incoming values from the BasicBlocks which 254 | * this branch instruction jumps to. 255 | * It uses getAllIncomingValuesFromPHIs. 256 | * 257 | * @param br The BranchInstruction to follow 258 | * 259 | * @return a vector of instruction pointers. 260 | * Same as getAllIncomingValuesFromPHIs 261 | */ 262 | static std::vector getAllIncomingValuesFromBranch(BranchInst* br); 263 | 264 | /** 265 | * @brief Returns the name of the array we are accessing. This gets a pointer to Store/Load 266 | * command and returns the 'name' of the array they are reading or writing to. 267 | * 268 | * @param inst The Store or Load instruction. 269 | * 270 | * @return the name of the array we are accessing. For example 'A' and Bitwidth 271 | */ 272 | ArrayInfo getVariableNameFromMemoryCommand(Instruction* inst); //JAWAD 273 | 274 | /// is this opcode only virtual and should not cause any delay ? 275 | bool m_empty; 276 | /// is this opcode a branch opcode which must come last? 277 | bool m_last; 278 | /// name of this opcode 279 | string m_opcodeName; 280 | /// it's place in the basic block, after scheduling 281 | unsigned int m_place; 282 | /// instructions which are used for dependency calculations 283 | /// these instructions are not mapped directly to uOps. 284 | set m_usedInst; 285 | /// dependencies it has on other opcodes 286 | set m_dependencies; 287 | /// assign part, if needed 288 | assignPartEntry* m_assignPart; 289 | /// name of BasicBlock/State this hw is scheduled at 290 | string m_stateName; 291 | /// the actual uOP instructions 292 | vector m_iv; 293 | /// Is this abstractHWOpcode has to be last in BB ? 294 | bool m_mustBeLast; 295 | }; // class abstractHWOpcode 296 | 297 | 298 | } //end of namespace 299 | #endif // h guard 300 | -------------------------------------------------------------------------------- /Synthesis/designScorer.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "designScorer.h" 3 | #include "../params.h" 4 | 5 | namespace xVerilog { 6 | 7 | 8 | double designScorer::getDesignFrequency() { 9 | 10 | map resourceMap = 11 | machineResourceConfig::getResourceTable(); 12 | 13 | unsigned int mul_pipes = resourceMap["delay_mul"]; 14 | unsigned int shl_pipes = resourceMap["delay_shl"]; 15 | unsigned int div_pipes = resourceMap["delay_div"]; 16 | 17 | 18 | unsigned int min_stages = 19 | std::min(mul_pipes, std::min(shl_pipes,div_pipes)); 20 | 21 | double max_time = 3.5; 22 | 23 | if (0 == min_stages) max_time = 100.0; 24 | else if (1 == min_stages) max_time = 11.112; 25 | else if (2 == min_stages) max_time = 6.737; 26 | else if (3 == min_stages) max_time = 5.190; 27 | else if (4 == min_stages) max_time = 4.852; 28 | else if (5 == min_stages) max_time = 3.856; 29 | else if (6 == min_stages) max_time = 3.645; 30 | else if (7 == min_stages) max_time = 3.630; 31 | else if (min_stages < 16) max_time = 3.60; 32 | 33 | /*double max_time = 0; 34 | for (listSchedulerVector::iterator it = m_basicBlocks.begin(); it != m_basicBlocks.end(); ++it) { 35 | max_time = std::max(max_time, getBasicBlockMaxDelay(*it)); 36 | }*/ 37 | 38 | return max_time; 39 | } 40 | 41 | unsigned int designScorer::getDesignClocks() { 42 | unsigned int max_loop_clocks = 0; 43 | unsigned int max_clocks = 0; 44 | for (listSchedulerVector::iterator it = m_basicBlocks.begin(); 45 | it != m_basicBlocks.end(); ++it) { 46 | // Is this BasicBlock a part of a loop ? 47 | if (m_loopInfo->getLoopFor((*it)->getBB())) { 48 | max_loop_clocks = std::max(max_loop_clocks, getBasicBlockClocks(*it)); 49 | } 50 | max_clocks = std::max(max_clocks, getBasicBlockClocks(*it)); 51 | } 52 | if (max_loop_clocks != 0) return max_loop_clocks; 53 | return max_clocks; 54 | } 55 | 56 | double designScorer::getLoopBlocksCount() { 57 | unsigned int bbs, lbbs; 58 | bbs = 0; 59 | lbbs = 0; 60 | 61 | for (listSchedulerVector::iterator it = m_basicBlocks.begin(); it != m_basicBlocks.end(); ++it) { 62 | bbs+=(*it)->length(); 63 | // Is this BasicBlock a part of a loop ? 64 | if (m_loopInfo->getLoopFor((*it)->getBB())) { 65 | lbbs+=(*it)->length(); 66 | } 67 | } 68 | 69 | if (lbbs==0) lbbs = bbs; //if no loops then all of the design is interesting 70 | 71 | return (double)lbbs/(double)bbs; 72 | } 73 | 74 | double designScorer::getBasicBlockMaxDelay(listScheduler* ls) { 75 | double max_delay = 0; 76 | //for each cycle in this basic block 77 | for (unsigned int cycle=0; cyclelength();cycle++) { 78 | vector inst = ls->getInstructionForCycle(cycle); 79 | //for each instruction in cycle, find it's delay ... 80 | for (vector::iterator ii = inst.begin(); ii != inst.end(); ++ii) { 81 | max_delay = std::max(max_delay, getDelayForInstruction(*ii)); 82 | } 83 | }// for each cycle 84 | 85 | return max_delay; 86 | } 87 | 88 | 89 | // 90 | // Times for Virtex4 XC4VLX25 91 | // 92 | // 93 | double designScorer::getDelayForInstruction(Instruction *inst) { 94 | 95 | const double BASE_ASSIGN_DELAY = 1.849; 96 | 97 | double delay = 0; 98 | 99 | if (dyn_cast(inst)) delay = BASE_ASSIGN_DELAY; 100 | if (dyn_cast(inst)) delay = BASE_ASSIGN_DELAY; 101 | if (dyn_cast(inst)) delay = BASE_ASSIGN_DELAY; 102 | if (dyn_cast(inst)) delay = BASE_ASSIGN_DELAY; 103 | 104 | // Converting bits from one format to another 105 | if (dyn_cast(inst)) delay = 0.1; 106 | if (dyn_cast(inst)) delay = 0.1; 107 | if (dyn_cast(inst)) delay = 0.1; 108 | if (dyn_cast(inst)) delay = 0.1; 109 | if (dyn_cast(inst)) delay = 0.1; 110 | 111 | // Binary instructions 112 | if (dyn_cast(inst)) { 113 | BinaryOperator* bin = (BinaryOperator*) inst; 114 | // Simple binary functions 115 | if (bin->getOpcode() == Instruction::Add || bin->getOpcode() == Instruction::Sub) { 116 | delay = 1.849; 117 | } 118 | if (bin->getOpcode() == Instruction::UDiv ) { 119 | delay = 10; // can't synthesis this 120 | } 121 | if (bin->getOpcode() == Instruction::Mul ) { 122 | delay = 7.72; 123 | } 124 | if (bin->getOpcode() == Instruction::And || 125 | bin->getOpcode() == Instruction::Or || 126 | bin->getOpcode() == Instruction::Xor) { 127 | delay = BASE_ASSIGN_DELAY * 1.3; // I guess that it's almost free 128 | } 129 | 130 | // Shift, may be constant (routing ), may be assign part (shl module) 131 | if ((bin->getOpcode()) == Instruction::Shl || bin->getOpcode() == Instruction::LShr) { 132 | // shift by constant 133 | if (dyn_cast(bin->getOperand(1))) delay = 0; 134 | // Assign part 135 | delay = BASE_ASSIGN_DELAY; 136 | } 137 | } 138 | 139 | const Type* Ty = inst->getType(); 140 | // if we don't know this type, don't normalize it 141 | if (!Ty->isPrimitiveType() || !Ty->isInteger() || !Ty->isSized()) return delay; 142 | if (Ty->getTypeID() == Type::IntegerTyID) { 143 | unsigned NBits = cast(Ty)->getBitWidth(); 144 | delay = (delay/32)*NBits; 145 | } 146 | 147 | return delay; 148 | } 149 | 150 | unsigned int designScorer::getDesignSizeInGates(Function* F) { 151 | 152 | unsigned int totalGateSize = 0; 153 | 154 | map resourceMap = 155 | machineResourceConfig::getResourceTable(); 156 | 157 | unsigned int mul_count = resourceMap["mul"]; 158 | unsigned int div_count = resourceMap["div"]; 159 | unsigned int shl_count = resourceMap["shl"]; 160 | 161 | totalGateSize += mul_count*1088 + div_count*1500 + shl_count*1000; 162 | 163 | for (inst_iterator i = inst_begin(*F), e = inst_end(*F); i != e; ++i) { 164 | totalGateSize += getInstructionSize(&*i); 165 | } 166 | return totalGateSize; 167 | } 168 | 169 | int designScorer::getInstructionSize(Instruction* inst) { 170 | const Type* Ty = inst->getType(); 171 | if (!Ty->isPrimitiveType() || !Ty->isInteger() || !Ty->isSized()) return 1; 172 | unsigned int gates = 0; 173 | 174 | switch (Ty->getTypeID()) { 175 | case Type::VoidTyID: { 176 | gates = 1; // one bit 177 | } 178 | case Type::PointerTyID: { // define the verilog pointer type 179 | gates = m_pointerSize; // 32bit for our pointers 180 | } 181 | case Type::IntegerTyID: { // define the verilog integer type 182 | unsigned NBits = cast(Ty)->getBitWidth(); 183 | gates = NBits; 184 | } 185 | default: gates = 1; 186 | } 187 | 188 | if (BinaryOperator *calc = dyn_cast(inst)) { 189 | if (calc->getOpcode() == Instruction::LShr) { 190 | gates *= 7; 191 | } 192 | if (calc->getOpcode() == Instruction::AShr) { 193 | gates *= 7; 194 | } 195 | if (calc->getOpcode() == Instruction::Sub) { 196 | gates *= 5; 197 | } 198 | if (calc->getOpcode() == Instruction::Add) { 199 | gates *= 5; 200 | } 201 | if (calc->getOpcode() == Instruction::Shl) { 202 | gates *= 9; 203 | } 204 | } 205 | return gates; 206 | 207 | } 208 | 209 | 210 | } // namespace 211 | -------------------------------------------------------------------------------- /Synthesis/designScorer.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_DESIGN_SCORER_H 3 | #define LLVM_DESIGN_SCORER_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/DerivedTypes.h" 16 | #include "llvm/Analysis/LoopInfo.h" 17 | #include "llvm/Support/InstIterator.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "listScheduler.h" 27 | 28 | using namespace llvm; 29 | 30 | namespace xVerilog { 31 | 32 | /* 33 | * @brief A class for evaluating the score of a scheduling job based on the frequency 34 | * and number of clocks. 35 | */ 36 | class designScorer { 37 | public: 38 | /** 39 | * @brief C'tor 40 | * 41 | * @param design A listScheduler object who's design 42 | * we want to examine 43 | */ 44 | designScorer(LoopInfo* LInfo):m_loopInfo(LInfo){ 45 | // get the configuration of the units from the command line 46 | map resourceMap = machineResourceConfig::getResourceTable(); 47 | m_pointerSize = resourceMap["mem_wordsize"]; 48 | }; 49 | 50 | /** 51 | * @brief Adds a list scheduler to the list of schedulers to evaluate 52 | * 53 | * @param ls the scheduler to add 54 | */ 55 | void addListScheduler(listScheduler* ls) { 56 | m_basicBlocks.push_back(ls); 57 | } 58 | 59 | /** 60 | * 61 | * @return time in usec 62 | */ 63 | unsigned int getDesignClocks(); 64 | /** 65 | * @brief Returns the max frequency that the design can stand 66 | * 67 | * @return max frequenct 68 | */ 69 | double getDesignFrequency(); 70 | 71 | /** 72 | * @returns number between zero and one, the percentage of all BasicBlocks which are 73 | * inside a loop. 74 | */ 75 | double getLoopBlocksCount(); 76 | 77 | /** 78 | * @brief approximates the number of flip flops this circuit takes 79 | * 80 | * @param ls the basic block to eval 81 | * 82 | * @return 83 | */ 84 | unsigned int getDesignSizeInGates(Function* F); 85 | private: 86 | 87 | /** 88 | * @brief Get the number of clocks it takes a BasicBlock to be executed (steps) 89 | * 90 | * @param ls the listScheduler which scheduled the BB 91 | * 92 | * @return clocks to complete the bb 93 | */ 94 | unsigned int getBasicBlockClocks(listScheduler* ls) { return ls->length(); } 95 | 96 | /** 97 | * @brief Evaluate the max delay of a single BasicBlock in usec 98 | * 99 | * @param ls the block to evaluate 100 | * 101 | * @return the time in usec to execute the longest instruction 102 | */ 103 | double getBasicBlockMaxDelay(listScheduler* ls); 104 | 105 | /** 106 | * @brief Returns the physical hardware execution delay time in ns 107 | * 108 | * @param inst instruction to eval 109 | * 110 | * @return time in ns 111 | */ 112 | double getDelayForInstruction(Instruction *inst); 113 | 114 | /** 115 | * @brief approximates the number of flip flops this instruction takes 116 | * 117 | * @param inst , the instruction who's size we want to get 118 | * 119 | * @return in bits (flip flops) 120 | */ 121 | int getInstructionSize(Instruction* inst); 122 | /// a vector of schedulers to evaluate 123 | listSchedulerVector m_basicBlocks; 124 | LoopInfo* m_loopInfo; 125 | unsigned int m_pointerSize; 126 | }; 127 | 128 | 129 | } //end of namespace 130 | #endif // h guard 131 | -------------------------------------------------------------------------------- /Synthesis/globalVarsRegistry.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "globalVarsRegistry.h" 3 | 4 | namespace xVerilog { 5 | 6 | /// static variables 7 | Module* globalVarRegistry::m_module; 8 | map globalVarRegistry::m_map; 9 | vector globalVarRegistry::m_garbage; 10 | 11 | /// initial values 12 | Value* globalVarRegistry::Zero1 = ConstantInt::get(Type::Int1Ty, 0); 13 | Value* globalVarRegistry::One1 = ConstantInt::get(Type::Int1Ty, 1); 14 | Value* globalVarRegistry::Zero32 = ConstantInt::get(Type::Int32Ty, 0); 15 | Value* globalVarRegistry::One32 = ConstantInt::get(Type::Int32Ty, 1); 16 | 17 | void globalVarRegistry::destroy() { 18 | // destroy all variables that should be destroied 19 | // We do that so that we don't have dead values with users 20 | // flying around 21 | 22 | // destroy all keys in hash table (all global variables) 23 | for( map::iterator it = m_map.begin(); 24 | it != m_map.end(); ++it ) { 25 | // Replace all used of this variable with a null pointer 26 | it->second->replaceAllUsesWith(ConstantPointerNull::get(it->second->getType())); 27 | // Remove this global variable from its parent module 28 | it->second->removeFromParent(); 29 | // Delete it 30 | delete it->second; 31 | } 32 | 33 | // For each load instruction that we have modified 34 | for (vector::iterator it = m_garbage.begin(); it!=m_garbage.end();it++) { 35 | // Replace the users of this dummy instruction with zero; 36 | if (!(*it)->hasNUses(0)) (*it)->replaceAllUsesWith(ConstantInt::get((*it)->getType(),0)); 37 | // And delete it 38 | delete *it; 39 | } 40 | } 41 | 42 | const Type* globalVarRegistry::bitNumToType(int bitnum){ 43 | if (bitnum==64) return Type::Int64Ty; 44 | if (bitnum==32) return Type::Int32Ty; 45 | if (bitnum==16) return Type::Int16Ty; 46 | if (bitnum==8) return Type::Int8Ty; 47 | if (bitnum==1) return Type::Int1Ty; 48 | cerr<<"Unsupported bit addressing mode; "< 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | using namespace llvm; 24 | 25 | using std::map; 26 | using std::set; 27 | using std::vector; 28 | using std::pair; 29 | using std::string; 30 | 31 | namespace xVerilog { 32 | /* 33 | * This class holds a mapping between the names of the global variables and the 34 | * pointer to the actual data. This allows control of all of the global variables 35 | * in a single location. 36 | */ 37 | class globalVarRegistry { 38 | 39 | public: 40 | void init(Module *M) {m_module = M; } 41 | 42 | void destroy(); 43 | 44 | /* 45 | * add this variable to a list of instructions to be destructed on exit 46 | */ 47 | void trashWhenDone(Instruction* val) { m_garbage.push_back(val); } 48 | 49 | /* 50 | * gets or creates a global variable which will be destructed on exit 51 | * @params number of bits, it this a pointer, default value, name 52 | */ 53 | GlobalVariable* getGlobalVariableByName(string varName, 54 | int bits = 32, bool pointer = false ,int val = 0); 55 | 56 | GlobalVariable* getGlobalVariableByName(string varName, const Type* type); 57 | 58 | /* 59 | * Creates a type of the needed bit number. For example Int64Ty 60 | */ 61 | static const Type* bitNumToType(int bitnum); 62 | 63 | // some default values to use 64 | static Value *Zero1; 65 | static Value *One1; 66 | static Value *Zero32; 67 | static Value *One32; 68 | 69 | private: 70 | static Module* m_module; 71 | static map m_map; 72 | static vector m_garbage; 73 | }; 74 | 75 | 76 | } //end of namespace 77 | #endif // h guard 78 | -------------------------------------------------------------------------------- /Synthesis/instPriority.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "instPriority.h" 3 | 4 | namespace xVerilog { 5 | 6 | instructionPriority::instructionPriority(BasicBlock* BB) { 7 | this->BB = BB; 8 | calculateDeps(); 9 | } 10 | 11 | unsigned int instructionPriority::getLocalUses(Instruction* inst) { 12 | unsigned int uses = 0; 13 | // For all of the users of this instructions 14 | for (Instruction::use_iterator it = inst->use_begin(); it!= inst->use_end(); ++it) { 15 | // Which are really instructions 16 | if (Instruction* d = dyn_cast(*it)) { 17 | // And are in this basic block 18 | if (d->getParent() == BB) uses++; 19 | } 20 | } 21 | return uses; 22 | } 23 | 24 | set instructionPriority::getDependencies(Instruction* inst) { 25 | set deps; 26 | 27 | // We do not count PHINodes because they may create cyclic dependencies. 28 | // We only want to get dependencies which are within this BB's iteration. 29 | if (dyn_cast(inst)) { 30 | return deps; 31 | } 32 | 33 | // for all deps 34 | for (User::op_iterator dep_iter = inst->op_begin(); 35 | dep_iter != inst->op_end(); ++dep_iter){ 36 | // if this dep is an instruction rather then a parameter 37 | if (Instruction* dep = dyn_cast(*dep_iter)) { 38 | if (dep->getParent() == BB) 39 | deps.insert(dep); 40 | } 41 | } 42 | return deps; 43 | } 44 | 45 | 46 | void instructionPriority::calculateDeps() { 47 | set to_update; 48 | 49 | // Setup map for iterations 50 | for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { 51 | if (0 == getLocalUses(I)) { 52 | m_depth[I] = 1; 53 | to_update.insert(I); 54 | } else { 55 | // unused instructions are set to layer zero 56 | // which is the last layer 57 | m_depth[I] = 0; 58 | } 59 | } 60 | 61 | assert (m_depth.size() == BB->size() && "Map and BB are in different sizes"); 62 | // While there are opcodes to update 63 | // do the following iterations 64 | while(0 != to_update.size()) { 65 | 66 | // what to update next round 67 | set next_update; 68 | 69 | // for all instructions in the update list 70 | for (set::iterator it = to_update.begin(); 71 | it!= to_update.end(); ++it) { 72 | 73 | // for all instructions in the dependency list 74 | set deps = getDependencies(*it); 75 | for (set::iterator dp = deps.begin(); 76 | dp!= deps.end(); ++dp) { 77 | // Each opcode is assigned to the longest distance 78 | // either it's current distance or the path from the 79 | // dependency 80 | m_depth[*dp] = std::max(m_depth[*it] + 1, m_depth[*dp]); 81 | // we need to update the children of this opcode 82 | // in the next iteration 83 | next_update.insert(*dp); 84 | } 85 | } 86 | // prepare next iteration 87 | to_update.clear(); 88 | to_update.insert(next_update.begin(), next_update.end()); 89 | } 90 | } 91 | 92 | InstructionVector instructionPriority::getOrderedInstructions() { 93 | // a vector for storing th opcodes. The opcode with the highest 94 | // dependency height (are in the critical path) come first 95 | InstructionVector order; 96 | // terminators MUST come at the end of all opcodes 97 | InstructionVector terminators; 98 | 99 | assert (m_depth.size() == BB->size() && "Map and BB are in different sizes"); 100 | 101 | unsigned int maximum = 0; 102 | // find the opcode with the highest layer number 103 | for (InstPriorityMap::iterator it = m_depth.begin(); it != m_depth.end(); ++it) { 104 | maximum = std::max(it->second,maximum); 105 | } 106 | 107 | // start putting them in the layers, from last to first 108 | for (unsigned int iter=maximum+1; iter>0; --iter) { 109 | for (InstPriorityMap::iterator it = m_depth.begin(); it != m_depth.end(); ++it) { 110 | // if it is the turn of this BFS layer 111 | if ((iter-1) == it->second) { 112 | // terminators come at the end 113 | if (it->first->isTerminator()) { 114 | terminators.push_back(it->first); 115 | } else { 116 | order.push_back(it->first); 117 | } 118 | } 119 | } 120 | } 121 | // put terminators at the end of the order list 122 | order.insert(order.end(), terminators.begin(), terminators.end()); 123 | assert (order.size() == BB->size() && "Returning list in different sizes"); 124 | return order; 125 | } 126 | 127 | 128 | } // namespace 129 | -------------------------------------------------------------------------------- /Synthesis/instPriority.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_INST_PRIO_H 3 | #define LLVM_INST_PRIO_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/DerivedTypes.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "../utils.h" 25 | #include "abstractHWOpcode.h" 26 | 27 | using namespace llvm; 28 | 29 | 30 | namespace xVerilog { 31 | 32 | using std::vector; 33 | using std::map; 34 | 35 | /* 36 | * This class gives a scheduling priority for each one of the instructions 37 | * in a basic block based on a reasonable order. It gives 38 | * instructions which are in the critical pass the first priority. 39 | */ 40 | class instructionPriority { 41 | public: 42 | typedef map InstPriorityMap; 43 | 44 | /* 45 | *C'tor 46 | */ 47 | instructionPriority(BasicBlock* BB); 48 | 49 | /** 50 | * @brief return a topologically ordered instruction list 51 | * @return InstructionVector of instructions. First instruction should be 52 | * scheduled first. 53 | */ 54 | InstructionVector getOrderedInstructions(); 55 | private: 56 | /** 57 | * @brief Returns the number of uses this inst has 58 | * in this basic block 59 | */ 60 | unsigned int getLocalUses(Instruction* inst); 61 | 62 | /* 63 | * Return a list of all of the dependencies of instruction 64 | */ 65 | set getDependencies(Instruction* inst); 66 | 67 | /** 68 | * @brief Calculate the dependencies between the 69 | * different opcodes. Give each one of the nodes a BFS 70 | * score. 71 | */ 72 | void calculateDeps(); 73 | 74 | /// Holds the depth of each of the elements in the graph 75 | InstPriorityMap m_depth; 76 | 77 | /// hold the BasicBlock 78 | BasicBlock* BB; 79 | }; //class 80 | 81 | 82 | } //end of namespace 83 | #endif // h guard 84 | -------------------------------------------------------------------------------- /Synthesis/intrinsics.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "intrinsics.h" 3 | #include 4 | namespace xVerilog { 5 | 6 | 7 | string getIntrinsicForInstruction(CallInst *intrin, vector ¶ms) { 8 | std::stringstream ss; 9 | string macro_name = intrin->getCalledFunction()->getNameStr(); 10 | if (macro_name == "rotate_left") { 11 | assert(params.size()==3 && "rotate_left needs to have two params"); 12 | string var = params[1]; 13 | string offset = params[2]; 14 | ss<<"{" << var<<"[31-"< 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | using namespace llvm; 27 | using std::string; 28 | using std::vector; 29 | 30 | namespace xVerilog { 31 | 32 | string getIntrinsicForInstruction(CallInst *intrin, vector ¶ms); 33 | 34 | 35 | } //end of namespace 36 | #endif // h guard 37 | -------------------------------------------------------------------------------- /Synthesis/listScheduler.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #include "listScheduler.h" 3 | #include "instPriority.h" 4 | 5 | namespace xVerilog { 6 | 7 | resourceUnit::resourceUnit(string name, unsigned int id, unsigned int streamNum): 8 | m_name(name),m_id(id),m_seq(streamNum) { 9 | this->enlargeResourceTable(40); 10 | } 11 | 12 | void resourceUnit::enlargeResourceTable(unsigned int newSize) { 13 | assert(newSize < 1000000 && "Piecetable should not exceed 1M items"); 14 | for (unsigned int j=0; jenlargeResourceTable(cycleNum); 58 | assert(m_seq[sq].size() > cycleNum && "Cycle num is to large"); 59 | cycle.insert(cycle.begin(), m_seq[sq][cycleNum].begin(), m_seq[sq][cycleNum].end()); 60 | } 61 | return cycle; 62 | } 63 | 64 | bool resourceUnit::emptyAt(unsigned int streamID, unsigned int cycle) { 65 | this->enlargeResourceTable(cycle); 66 | assert(cycle < m_seq[streamID].size() && "placing instruction out of piecetable"); 67 | return (0 == m_seq[streamID][cycle].size()); 68 | } 69 | 70 | unsigned int resourceUnit::getBestSchedulingCycle(abstractHWOpcode* op) { 71 | 72 | unsigned int start = op->getFirstSchedulableSlot(); 73 | // "other units" may schedule on any available slot 74 | if (this->getName() == "other") return start; 75 | 76 | 77 | // search for an available slot: 78 | // move starting slot one forward and try to schedule slot 79 | while (true) { 80 | bool fit = true; 81 | for (unsigned int strm=0; strm < m_seq.size(); strm++) { 82 | for(unsigned int i=0; igetLength(); i++) { 83 | // if opcode cycle is not empty and also resource is not empty at this point 84 | if (!op->emptyAt(strm, i) && !emptyAt(strm, i+start)) { 85 | // then this place is not available 86 | fit = false; 87 | } 88 | } 89 | }//stream 90 | if (fit) { 91 | return start; 92 | } 93 | ++start; 94 | } 95 | } 96 | 97 | void resourceUnit::place(abstractHWOpcode* op, unsigned int place) { 98 | 99 | this->enlargeResourceTable(place); 100 | assert(place < m_seq[0].size() && "placing instruction out of piecetable"); 101 | 102 | op->place(place, getId()); 103 | // for each stream in the opcode 104 | for (unsigned int strm=0; strm < m_seq.size(); strm++) { 105 | // for each cycle in the hardware opcode 106 | for(unsigned int i=0; igetLength(); i++) { 107 | // for each operation 108 | InstructionCycle cycle = op->cycleAt(strm,i); 109 | for (InstructionCycle::iterator it = cycle.begin(); it!=cycle.end();it++) { 110 | // add the operation to the local sequence of operations 111 | m_seq[strm][place+i].push_back(*it); 112 | } 113 | } 114 | } 115 | } 116 | 117 | string resourceUnit::toString() { 118 | std::stringstream sb; 119 | for (unsigned strm=0; strm availableResources) { 160 | resourceUnit* best = NULL; 161 | unsigned int less = 10000; 162 | for (vector::iterator un = availableResources.begin(); 163 | un!=availableResources.end();++un) { 164 | if ((*un)->takenSlots() < less) { 165 | less = (*un)->takenSlots(); 166 | best = *un; 167 | } 168 | } 169 | return best; 170 | } 171 | 172 | 173 | /// list scheduler below 174 | 175 | listScheduler::listScheduler(BasicBlock* BB,llvm::TargetData* TD):TD(TD),//JAWAD 176 | m_bb(BB), 177 | m_memoryPorts(getMemoryPortDeclerations(BB->getParent(),TD)) { //JAWAD 178 | 179 | map rt = machineResourceConfig::getResourceTable(); 180 | 181 | for (MemportMap::iterator k = m_memoryPorts.begin(); k!=m_memoryPorts.end(); ++k) { 182 | // Add a 'resource' with this name 183 | addResource("mem_" + k->first, rt["memport"]); 184 | } 185 | 186 | addResource("mul", rt["mul"]); 187 | addResource("div", rt["div"]); 188 | addResource("shl", rt["shl"]); 189 | addResource("other",1); 190 | 191 | scheduleBasicBlock(BB); 192 | } 193 | 194 | vector listScheduler::getInstructionForCycle(unsigned int cycleNum) { 195 | vector ret; 196 | // for each unit in the processor 197 | for (vector::iterator it = m_units.begin(); it!=m_units.end(); ++it) { 198 | // for each of the collection of cycles from the different units 199 | InstructionCycle cycle = (*it)->getInstructionForCycle(cycleNum); 200 | for (InstructionCycle::iterator ins = cycle.begin(); ins!=cycle.end(); ++ins) { 201 | ret.push_back(*ins); 202 | } 203 | } 204 | return ret; 205 | } 206 | 207 | 208 | 209 | 210 | vector listScheduler::getAssignParts() { 211 | vector ret; 212 | // for each scheduled abstractHWOpcode 213 | for (vector::iterator it=m_ops.begin(); it!=m_ops.end();++it) { 214 | if ((*it)->getAssignPart()) { 215 | ret.push_back((*it)->getAssignPart()); 216 | } 217 | } 218 | return ret; 219 | } 220 | 221 | 222 | 223 | unsigned int listScheduler::length() { 224 | unsigned int len = 0; 225 | for(vector::iterator it = m_units.begin(); it!=m_units.end(); ++it) { 226 | len = std::max(len, (*it)->length()); 227 | } 228 | return len; 229 | } 230 | 231 | 232 | 233 | unsigned int listScheduler::getResourceIdForInstruction(Instruction* inst) { 234 | for(vector::iterator it = m_units.begin(); it!=m_units.end(); ++it) { 235 | if ((*it)->hasInstruction(inst)) return (*it)->getId(); 236 | } 237 | cerr<<"unable to find the resource unit for instruction "<getName()),2,TD); //JAWAD 261 | m_ops.push_back(op); 262 | // establish dependencies with previously generated opcodes 263 | for (vector::iterator depop = m_ops.begin(); depop!= m_ops.end(); ++depop) { 264 | op->addDependencyIfDepends(*depop); 265 | } 266 | } 267 | 268 | 269 | // populate the opcoded in the scheduling table 270 | // This is the actual scheduling of the abstract opcodes 271 | // For each vector, place it in best location 272 | for (vector::iterator depop = m_ops.begin(); depop!= m_ops.end(); ++depop) { 273 | vector availableUnits; 274 | resourceUnit* best_unit = NULL; 275 | unsigned int best_loc = 10000; 276 | // for each resource unit 277 | for (vector::iterator un = m_units.begin(); un!=m_units.end();++un) { 278 | // if this is the correct type of unit 279 | if ((*un)->isSameUnitType(*depop)) { 280 | unsigned int res = (*un)->getBestSchedulingCycle(*depop); 281 | if (res < best_loc) { 282 | best_loc = res; 283 | availableUnits.clear(); 284 | availableUnits.push_back(*un); 285 | } else if (res == best_loc) { 286 | availableUnits.push_back(*un); 287 | } 288 | } // if matches 289 | }// foreach unit 290 | 291 | // find the resourceUnit which has the least scheduled instructions 292 | // we do this to create muxes which are balanced. 293 | best_unit = resourceUnit::getLeastBusyResource(availableUnits); 294 | 295 | // After finding the best resource unit, schedule this opcode there 296 | assert(best_unit && "Unable to find best unit to schedule the opcode"); 297 | if ((*depop)->isMustBeLastOpcode()) { 298 | //cerr<<"placing at "<toString()<<"\n"; 299 | unsigned int cur_max_len = ((length()>0) ? length()-1 : 0) ; 300 | best_unit->place(*depop, std::max(cur_max_len, best_loc)); 301 | } else { 302 | // place this abstractHWOpcode in the right cycles 303 | best_unit->place(*depop, best_loc); 304 | } 305 | }// for each opcode 306 | 307 | //print list Scheduler 308 | // debug 309 | cerr<<"---=="<getBB()->getName()<<"["<length()<<"]==---\n"; 310 | for (vector::iterator un = m_units.begin(); un!=m_units.end();++un) { 311 | cerr<<(*un)->toString(); 312 | } 313 | 314 | cerr<<"resource usage: " 315 | <<"memport:"<::iterator it = m_units.begin(); it != m_units.end(); ++it) { 331 | if ((*it)->getName().find(resourceName) != std::string::npos) { 332 | if ((*it)->takenSlots() >0) { 333 | units++; 334 | } 335 | } 336 | } 337 | return units; 338 | } 339 | 340 | MemportMap listScheduler::getMemoryPortDeclerations(const Function* F,TargetData* TData) {//JAWAD 341 | assert(F && "not a function. cannot continue"); 342 | MemportMap memports; 343 | 344 | // For each parameter in function header 345 | for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) { //JAWAD 346 | unsigned NumBits; 347 | std::string name = I->getName(); 348 | if(const StructType *ST = abstractHWOpcode::isPtrToStructType(I)) { 349 | std::string field_name; 350 | for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) { 351 | //NumBits = abstractHWOpcode::getBitWidthFromType(ST->getElementType(i)); 352 | NumBits = TData->getTypeSizeInBits(ST->getElementType(i)); 353 | stringstream i_str; 354 | i_str << i; 355 | field_name = name + std::string("_field_") + i_str.str(); 356 | memports[field_name] = NumBits; 357 | }; 358 | NumBits = TData->getTypeSizeInBits(I->getType()); 359 | memports[name] = NumBits; 360 | }else{ 361 | NumBits = TData->getTypeSizeInBits(I->getType()); 362 | 363 | memports[name] = NumBits; 364 | }; 365 | } 366 | return memports; 367 | } 368 | 369 | 370 | } // namespace 371 | -------------------------------------------------------------------------------- /Synthesis/listScheduler.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_LIST_SCHED_H 3 | #define LLVM_LIST_SCHED_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/DerivedTypes.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "../utils.h" 25 | #include "../params.h" 26 | #include "abstractHWOpcode.h" 27 | 28 | 29 | 30 | using namespace llvm; 31 | 32 | using std::vector; 33 | using std::pair; 34 | using std::string; 35 | using std::map; 36 | 37 | namespace xVerilog { 38 | 39 | /* 40 | * Represents a hardware execution unit (such as an instance of an ALU 41 | * on a processor) 42 | */ 43 | class resourceUnit { 44 | public: 45 | /* 46 | * C'tor 47 | */ 48 | resourceUnit(string name, unsigned int id, unsigned int streamNum = 2); 49 | 50 | /* 51 | * @return the length of this resource unit in cycles which are scheduled 52 | */ 53 | unsigned int length(); 54 | 55 | /* 56 | * @return True if instruction inst is scheduled to run in this 57 | * resource unit 58 | */ 59 | bool hasInstruction(Instruction* inst); 60 | /* 61 | * @return all of the instructions for one given cycle 62 | */ 63 | InstructionCycle getInstructionForCycle(unsigned int cycleNum); 64 | /* 65 | * @return True if opcode 'op' is executable on this instruction unit 66 | */ 67 | bool isSameUnitType(abstractHWOpcode* op) { return (op->getName() == this->getName()); } 68 | /* 69 | * @return name of unit 70 | */ 71 | string getName() {return m_name;} 72 | /* 73 | * @return id of unit 74 | */ 75 | unsigned int getId() {return m_id;} 76 | /* 77 | * @return the best possible possition to schedule 'op' in this 78 | * instruction unit. 79 | */ 80 | unsigned int getBestSchedulingCycle(abstractHWOpcode* op); 81 | /* 82 | * Place the abstract opcode in possition 'place' 83 | */ 84 | void place(abstractHWOpcode* op, unsigned int place); 85 | /* 86 | * @return a printable ascii image for debug 87 | */ 88 | string toString(); 89 | 90 | /** 91 | * @return returns the number of cycles which are already assigned 92 | */ 93 | unsigned int takenSlots(); 94 | 95 | /** 96 | * @brief select the resource with the fewest number of resources scheduled to it. 97 | * This makes sure the different requests are spread evenly and 98 | * it creates less pressure on the MUXs. 99 | * 100 | * @param availableResources the available resources 101 | * 102 | * @return the resource unit which is the smallest. Null if nothing is available 103 | */ 104 | static resourceUnit* getLeastBusyResource(vector availableResources); 105 | private: 106 | 107 | /** 108 | * @brief Enlarge the resource table by 'count' cycles to make room 109 | * for scheduling of more instructions. 110 | * 111 | * @param newSize the new size of the table 112 | */ 113 | void enlargeResourceTable(unsigned int newSize); 114 | 115 | /** 116 | * @return are there any uOp instructions on a stream in a cycle 117 | */ 118 | bool emptyAt(unsigned int streamID, unsigned int cycle); 119 | /* 120 | * @return the length of this resource unit in cycles which are scheduled 121 | * @param the stream who's length we want 122 | */ 123 | unsigned int length(unsigned int streamID); 124 | 125 | /** 126 | * @return the best possible possition to schedule 'op' in the 127 | * given seq (seq_in or seq_out) 128 | */ 129 | static unsigned int getBestSchedulingCycle(abstractHWOpcode* op, InstructionSequence &seq); 130 | 131 | /// name of hardware unit 132 | string m_name; 133 | /// the id of this unit, used for placing opcodes 134 | unsigned int m_id; 135 | /// storage for the instructions 136 | vector m_seq; 137 | }; 138 | 139 | typedef map MemportMap; 140 | 141 | /* 142 | *The class which schedules the hardware opcodes in their 143 | * different locations. This class is the main entry point for the 144 | * scheduling. 145 | */ 146 | class listScheduler { 147 | public: 148 | /* 149 | *C'tor list scheduler 150 | */ 151 | listScheduler(BasicBlock* BB,TargetData* TD); //JAWAD 152 | /* 153 | * @return the BasicBlock that we are scheduling 154 | * 155 | */ 156 | BasicBlock* getBB() {return m_bb;} 157 | /* 158 | * @return vector instructions for a given cycle. 159 | */ 160 | vector getInstructionForCycle(unsigned int cycleNum); 161 | /* 162 | * @return vector all assign parts of this basic block 163 | */ 164 | vector getAssignParts(); 165 | /* 166 | * @returns the num of cycles for this BasicBlock schedule 167 | */ 168 | unsigned int length(); 169 | /* 170 | * @return the id of the resourceUnit which instruction inst is 171 | * scheduled in 172 | */ 173 | unsigned int getResourceIdForInstruction(Instruction* inst); 174 | 175 | /** 176 | * @brief Returns a list of memory port names and their decleration types 177 | * 178 | * @param F The function we want to scan 179 | * 180 | * @return A map of name to bitwidth 181 | */ 182 | static MemportMap getMemoryPortDeclerations(const Function* F,TargetData* ); //JAWAD 183 | InstructionVector skipped_instructions; 184 | TargetData* TD; 185 | private: 186 | /* 187 | * Add resources to the list of units where we schedule instructions. 188 | */ 189 | void addResource(string name, unsigned int count); 190 | 191 | /* 192 | * Populate the scheduler data structure with micro-commands 193 | * this may destroy the BasicBlock. (It will replace well formed 194 | * instructions with meaningless loads and stores to virtual 195 | * registers.) 196 | */ 197 | void scheduleBasicBlock(BasicBlock* BB); 198 | 199 | /** 200 | * 201 | * @param resourceName name of resource we want to evaluate 202 | * 203 | * @return the max usage of a certain resource at a single clock. 204 | * (Ex: How many mults do we use at the same time) 205 | */ 206 | unsigned int getMaxResourceUsage(std::string resourceName); 207 | 208 | 209 | /// Saves the different virtual execution units of the 210 | // processor 211 | vector m_units; 212 | /// name of BasicBlock in printable form 213 | BasicBlock* m_bb; 214 | /// lists all of the abstractHWOpcodes which were scheduled 215 | vector m_ops; 216 | /// A list of all memory ports and their bitwidth 217 | MemportMap m_memoryPorts; 218 | }; //class 219 | 220 | typedef vector listSchedulerVector; 221 | 222 | } //end of namespace 223 | #endif // h guard 224 | -------------------------------------------------------------------------------- /Synthesis/verilogLang.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | #ifndef LLVM_VERILOG_LANG_H 3 | #define LLVM_VERILOG_LANG_H 4 | 5 | #include "llvm/Pass.h" 6 | #include "llvm/Function.h" 7 | #include "llvm/Instructions.h" 8 | #include "llvm/Constants.h" 9 | #include "llvm/ADT/StringExtras.h" 10 | #include "llvm/Support/Streams.h" 11 | #include "llvm/Module.h" 12 | #include "llvm/ADT/Statistic.h" 13 | #include "llvm/ADT/SmallVector.h" 14 | #include "llvm/Support/CFG.h" 15 | #include "llvm/DerivedTypes.h" 16 | 17 | #include "llvm/Support/Mangler.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "listScheduler.h" 26 | #include "../utils.h" 27 | #include "../params.h" 28 | 29 | class verilogLanguage; 30 | 31 | using namespace llvm; 32 | 33 | using std::vector; 34 | using std::pair; 35 | using std::string; 36 | using std::stringstream; 37 | 38 | namespace xVerilog { 39 | 40 | class verilogLanguage; 41 | 42 | /* 43 | * This class creates the string which represents the assign part in verilog. This is 44 | *the mux which wraps each of the execution units. 45 | */ 46 | class assignPartBuilder { 47 | public: 48 | assignPartBuilder(const string& name, const string& op): m_name(name),m_op(op) {} 49 | 50 | void addPart(assignPartEntry* part) {m_parts.push_back(part);} 51 | /* 52 | * @returns a string with the verilog representation of the assign part added 53 | */ 54 | string toString(verilogLanguage* abop); 55 | 56 | private: 57 | string m_name; 58 | string m_op; 59 | vector m_parts; 60 | 61 | }; 62 | 63 | class verilogLanguage { 64 | 65 | public: 66 | verilogLanguage(Module *module, Mangler *mang,TargetData* TD):m_module(module),m_mang(mang),TD(TD){//JAWAD 67 | 68 | map rt = machineResourceConfig::getResourceTable(); 69 | m_pointerSize = rt["membus_size"]; 70 | m_memportNum = rt["memport"]; 71 | } 72 | 73 | // print a value as either an expression or as a variable name 74 | string evalValue(Value* val); 75 | 76 | /// print all instructions which are inlineable 77 | string printInlinedInstructions(Instruction* inst); 78 | 79 | /// print list scheduler of a single BasicBlock 80 | string printBasicBlockControl(listScheduler *ls); 81 | string printBasicBlockDatapath(listScheduler *ls); 82 | 83 | string printStoreInst(Instruction* inst, int unitNum, int cycleNum); 84 | 85 | string printLoadInst(Instruction* inst, int unitNum, int cycleNum); 86 | 87 | string printBinaryOperatorInst(Instruction* inst, int unitNum, int cycleNum); 88 | 89 | string printReturnInst(Instruction* inst); 90 | string printSelectInst(Instruction* inst); 91 | 92 | string printZxtInst(Instruction* inst); 93 | string printBitCastInst(Instruction* inst); //JAWAD 94 | 95 | string printIntToPtrInst(Instruction* inst); 96 | 97 | string printAllocaInst(Instruction* inst); 98 | 99 | string printPHICopiesForSuccessor(BasicBlock *CurBlock,BasicBlock *Successor); 100 | 101 | string printBranchInst(Instruction* inst); 102 | 103 | string printCmpInst(Instruction* inst); 104 | 105 | string printPHINode(Instruction* inst); 106 | string getGetElementPtrInst(Instruction* inst); 107 | string printGetElementPtrInst(Instruction* inst); 108 | 109 | string GetValueName(const Value *Operand); 110 | 111 | bool isInstructionDatapath(Instruction *inst); 112 | 113 | string printInstruction(Instruction *inst, unsigned int resourceId); 114 | 115 | string getArgumentListDecl(const Function &F, const string& prefix); 116 | 117 | string getTestBench(Function &F); 118 | string getTypeDecl(const Type *Ty, bool isSigned, const std::string &NameSoFar); 119 | string getMemDecl(Function *F); 120 | string getClockHeader(); 121 | string getClockFooter(); 122 | string getCaseHeader(); 123 | string getCaseFooter(); 124 | string getModuleFooter(); 125 | string getFunctionLocalVariables(listSchedulerVector lsv); 126 | unsigned int getNumberOfStates(listSchedulerVector &lsv); 127 | string getStateDefs(listSchedulerVector &lsv); 128 | string printAssignPart(vector ass, verilogLanguage* lang); 129 | string getAssignmentString(listSchedulerVector lv); 130 | string getIntrinsic(Instruction* inst); 131 | string printIntrinsic(Instruction* inst); 132 | 133 | string getFunctionSignature(const Function *F, const std::string Instance=""); 134 | 135 | string getBRAMDefinition(unsigned int wordBits, unsigned int addressBits); 136 | 137 | string createBinOpModule(string opName, string symbol, unsigned int stages); 138 | 139 | private: 140 | Module* m_module; 141 | Mangler* m_mang; 142 | TargetData* TD; //JAWAD 143 | /// The number of memory ports to render in this design 144 | unsigned int m_memportNum; 145 | unsigned int m_pointerSize; 146 | };//class 147 | } //end of namespace 148 | #endif // h guard 149 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /params.cpp: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | 3 | #include "params.h" 4 | 5 | namespace xVerilog { 6 | 7 | // the parser method for our integer parser 8 | bool UnitNumParser::parse(cl::Option &O, const char *ArgName, 9 | const std::string &Arg, unsigned &Val) { 10 | const char *ArgStart = Arg.c_str(); 11 | char *End; 12 | // Parse integer part, leaving 'End' pointing to the first non-integer char 13 | Val = (unsigned)strtol(ArgStart, &End, 0); 14 | //cerr<<"Parsing "< machineResourceConfig::getResourceTable() { 56 | map myMap; 57 | myMap["memport"] = param_mem_num; 58 | myMap["mul"] = param_mul_num; 59 | myMap["div"] = param_div_num; 60 | myMap["shl"] = param_shl_num; 61 | 62 | myMap["mem_wordsize"] = mem_wordsize; 63 | myMap["delay_memport"] = delay_mem_num; 64 | myMap["delay_mul"] = delay_mul_num; 65 | myMap["delay_div"] = delay_div_num; 66 | myMap["delay_shl"] = delay_shl_num; 67 | myMap["membus_size"] = membus_size; 68 | 69 | myMap["inline_op_to_wire"] = inline_wire; 70 | myMap["include_size"] = include_size; 71 | myMap["include_freq"] = include_freq; 72 | myMap["include_clocks"] = include_clocks; 73 | return myMap; 74 | } 75 | 76 | } // namespace 77 | -------------------------------------------------------------------------------- /params.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | 3 | #ifndef LLVM_PARAMS_H 4 | #define LLVM_PARAMS_H 5 | 6 | #include "llvm/Pass.h" 7 | #include "llvm/Function.h" 8 | #include "llvm/Instructions.h" 9 | #include "llvm/Constants.h" 10 | #include "llvm/ADT/StringExtras.h" 11 | #include "llvm/Support/Streams.h" 12 | #include "llvm/Module.h" 13 | #include "llvm/ADT/Statistic.h" 14 | #include "llvm/ADT/SmallVector.h" 15 | #include "llvm/Support/CFG.h" 16 | #include "llvm/DerivedTypes.h" 17 | #include "llvm/Support/CommandLine.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | using std::map; 25 | using std::string; 26 | using std::stringstream; 27 | 28 | using namespace llvm; 29 | 30 | namespace xVerilog { 31 | 32 | // define the integer parser 33 | struct UnitNumParser : public cl::basic_parser { 34 | // parse - Return true on error. 35 | bool parse(cl::Option &O, const char *ArgName, const std::string &ArgValue, 36 | unsigned &Val); 37 | }; 38 | 39 | typedef cl::opt UnitNumParserOption; 40 | 41 | class machineResourceConfig { 42 | public: 43 | /* 44 | * Load all of the values into a structure which will be used by the scheduler 45 | * to build the hardware description table. 46 | */ 47 | static map getResourceTable(); 48 | static string chrsubst(string str , int ch, int ch2) { //JAWAD 49 | char *s1 = new char [str.size()+1]; 50 | strcpy (s1, str.c_str()); 51 | int count = 0; /* The count to return */ 52 | char *wrk = strchr(s1, ch); /* Find first char in s1 */ 53 | while (wrk) { /* While we have matches */ 54 | *wrk = (char) ch2; /* Replace the character */ 55 | count++, wrk++; /* Increment the count & pointer */ 56 | wrk = strchr(wrk, ch); /* Search for next occurance */ 57 | } 58 | //return count; /* Return the count */ 59 | return string(s1); 60 | } 61 | private: 62 | static UnitNumParserOption param_mem_num; 63 | static UnitNumParserOption param_mul_num; 64 | static UnitNumParserOption param_div_num; 65 | static UnitNumParserOption param_shl_num; 66 | static UnitNumParserOption delay_mem_num; 67 | static UnitNumParserOption delay_mul_num; 68 | static UnitNumParserOption delay_div_num; 69 | static UnitNumParserOption delay_shl_num; 70 | static UnitNumParserOption mem_wordsize; 71 | static UnitNumParserOption membus_size; 72 | static UnitNumParserOption inline_wire; 73 | static UnitNumParserOption include_size; 74 | static UnitNumParserOption include_freq; 75 | static UnitNumParserOption include_clocks; 76 | }; //class 77 | 78 | } // namespace 79 | 80 | #endif // h guard 81 | 82 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | /* Nadav Rotem - C-to-Verilog.com */ 2 | 3 | #ifndef LLVM_SCHED_UTILS_H 4 | #define LLVM_SCHED_UTILS_H 5 | 6 | #include "llvm/Support/Mangler.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace llvm; 15 | 16 | using std::set; 17 | using std::vector; 18 | using std::pair; 19 | using std::string; 20 | using std::stringstream; 21 | 22 | namespace { 23 | 24 | /* 25 | * Set the terminal to color mode. Each line from this point will 26 | * be printed in color (white over blue). 27 | */ 28 | std::string xBlue() { 29 | return "\033[44;37;5m"; 30 | } 31 | 32 | /* 33 | * Set the terminal to color mode. Each line from this point will 34 | * be printed in color (white over blue). 35 | */ 36 | std::string xRed() { 37 | return "\033[22;31;5m"; 38 | } 39 | 40 | /* 41 | * Reset the terminal to it's regular color mode 42 | */ 43 | std::string xReset() { 44 | return "\033[0m"; 45 | } 46 | 47 | void logPassMessage(std::string passName,int line ,std::string message, bool good=true) { 48 | if (good) { 49 | cerr<= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || 66 | (ch >= '0' && ch <= '9') || ch == '_')) 67 | VarName += '_'; 68 | else 69 | VarName += ch; 70 | } 71 | return VarName; 72 | } 73 | 74 | string valueToString(Mangler* mang ,const Value *Operand) { 75 | std::string Name; 76 | 77 | const ConstantInt* CI = dyn_cast(Operand); 78 | 79 | if (CI && !isa(CI)) { 80 | stringstream ss; 81 | const Type* Ty = CI->getType(); 82 | if (Ty == Type::Int1Ty) 83 | ss<<((CI->getZExtValue() ? "1" : "0")); 84 | else { 85 | ss << "("; 86 | if (CI->isMinValue(true)) ss <<"-"<< CI->getZExtValue() <<""; 87 | else ss << CI->getSExtValue(); 88 | ss << ")"; 89 | } 90 | return ss.str(); 91 | } 92 | 93 | 94 | if (!isa(Operand) && Operand->getName() != "") { 95 | std::string VarName; 96 | 97 | Name = Operand->getName(); 98 | 99 | VarName = toPrintable(Name); 100 | 101 | const Type* tp = Operand->getType(); 102 | if (tp->isInteger()) { 103 | Name = "i_" + VarName; 104 | } else if(tp->isSized()) { 105 | Name = "p_" + VarName; 106 | } else { 107 | Name = "o_" + VarName; 108 | } 109 | return Name;//JAWAD 110 | 111 | } 112 | if(isa (Operand)){ //JAWAD 113 | return "(0) /* NULL */"; 114 | } 115 | //TODO: pass mang to this method ... 116 | Name = mang->getValueName(Operand); 117 | 118 | 119 | return Name; 120 | } 121 | 122 | 123 | 124 | 125 | } //end of namespace 126 | #endif // h guard 127 | -------------------------------------------------------------------------------- /vcc.sh: -------------------------------------------------------------------------------- 1 | TMPFILE="/tmp/file.bc" 2 | LLVM="$HOME/llvm-2.5/Release" 3 | LLVM_GCC="$HOME/llvm-gcc/install/" 4 | 5 | echo "This is the VCC command line tool. Usage vcc.sh source.c dst.v" 6 | 7 | UNT="-units_mul=4 -units_div=1 -units_memport=1 -units_shl=1" 8 | DLY="-delay_mul=5 -delay_div=5 -delay_memport=1 -delay_shl=5" 9 | WRE="-inline_op_to_wire=4 " 10 | DBG="-include_size=1 -include_clocks=1 -include_freq=1" 11 | MEM="-mem_wordsize=32 -membus_size=16" 12 | SYNFLAGS="$UNT $DLY $WRE $DBG $MEM" 13 | 14 | #OPTFLAGS="-unroll-threshold=20 -inline-threshold=4096 -inline -loopsimplify -loop-rotate -loop-unroll -std-compile-opts -indvars -simplifycfg" #-parallel_balance #-reduce_bitwidth -detect_arrays" 15 | OPTFLAGS="-unroll-threshold=512 -inline-threshold=4096 -inline -loopsimplify -loop-rotate -std-compile-opts -loop-unroll -indvars -simplifycfg -parallel_balance" #-reduce_bitwidth -detect_arrays" 16 | MYFLAGS="-parallel_balance -reduce_bitwidth " #-detect_arrays" 17 | 18 | rm -f $TMPFILE 19 | rm -f /tmp/dis.txt /tmp/dis1.txt /tmp/dis2.txt /tmp/dis3.txt /tmp/dis4.txt 20 | 21 | $LLVM_GCC/bin/llvm-g++ -emit-llvm -c $1 -o $TMPFILE 22 | $LLVM/bin/llvm-dis $TMPFILE -o /tmp/dis1.txt 23 | $LLVM/bin/opt -load=$LLVM/lib/LLVMPrepareSynthesis.so $OPTFLAGS $MEM $TMPFILE -o $TMPFILE -f 24 | $LLVM/bin/llvm-dis $TMPFILE -o /tmp/dis2.txt 25 | $LLVM/bin/opt -load=$LLVM/lib/LLVMPrepareSynthesis.so -dce -ms -adce $TMPFILE -o $TMPFILE -f 26 | $LLVM/bin/llvm-dis $TMPFILE -o /tmp/dis3.txt 27 | $LLVM/bin/opt -load=$LLVM/lib/LLVMPrepareSynthesis.so -dse -std-compile-opts $MYFLAGS $TMPFILE -o $TMPFILE -f 28 | $LLVM/bin/llvm-dis $TMPFILE -o /tmp/dis4.txt 29 | $LLVM/bin/llc -load=$LLVM/lib/LLVMSynthesis.so -march=v $SYNFLAGS $TMPFILE -f -o=$2 30 | 31 | --------------------------------------------------------------------------------