aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target/PIC16/PIC16AsmPrinter.cpp
blob: 549e2d9b471b1fb5683fbdeae04eaae13ef47b6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
//===-- PIC16AsmPrinter.cpp - PIC16 LLVM assembly writer ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a printer that converts from our internal representation
// of machine-dependent LLVM code to PIC16 assembly language.
//
//===----------------------------------------------------------------------===//

#include "PIC16AsmPrinter.h"
#include "PIC16TargetAsmInfo.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/DwarfWriter.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Mangler.h"
#include "llvm/CodeGen/DwarfWriter.h"
#include "llvm/CodeGen/MachineModuleInfo.h"

using namespace llvm;

#include "PIC16GenAsmWriter.inc"

inline static bool isLocalToFunc (std::string &FuncName, std::string &VarName) {
  if (VarName.find(FuncName + ".auto.") != std::string::npos 
      || VarName.find(FuncName + ".arg.") != std::string::npos)
    return true;

  return false;
}

inline static bool isLocalName (std::string &Name) {
  if (Name.find(".auto.") != std::string::npos 
      || Name.find(".arg.") != std::string::npos) 
    return true;

  return false;
}

bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
  std::string NewBank = "";
  unsigned Operands = MI->getNumOperands();
  if (Operands > 1) {
    // If we have a Global address or external symbol then we need to print 
    // banksel for it. 
    unsigned BankSelVar = 0;
    MachineOperand Op = MI->getOperand(BankSelVar);
    while (BankSelVar < Operands-1) {
      Op = MI->getOperand(BankSelVar);
      if ((Op.getType() ==  MachineOperand::MO_GlobalAddress) ||
          (Op.getType() ==  MachineOperand::MO_ExternalSymbol))
        break;
      BankSelVar++;
    }
    if (BankSelVar < Operands-1) {
      unsigned OpType = Op.getType();
      if (OpType == MachineOperand::MO_GlobalAddress ) 
        NewBank = Op.getGlobal()->getSection(); 
      else {
        // External Symbol is generated for temp data and arguments. They are 
        // in fpdata.<functionname>.# section.
        std::string ESName = Op.getSymbolName();
        int index = ESName.find_first_of(".");
        std::string FnName = ESName.substr(0,index);
        NewBank = "fpdata." + FnName +".#";
      }
      // Operand after global address or external symbol should be  banksel.
      // Value 1 for this operand means we need to generate banksel else do not
      // generate banksel.
      const MachineOperand &BS = MI->getOperand(BankSelVar+1);
      // If Section names are same then the variables are in same section.
      // This is not true for external variables as section names for global
      // variables in all files are same at this time. For eg. initialized 
      // data in put in idata.# section in all files. 
      if ((BS.getType() == MachineOperand::MO_Immediate 
          && (int)BS.getImm() == 1) 
          && ((Op.isGlobal() && Op.getGlobal()->hasExternalLinkage()) ||
           (NewBank.compare(CurBank) != 0))) { 
        O << "\tbanksel ";
        printOperand(MI, BankSelVar);
        O << "\n";
        CurBank = NewBank;
      }
    }
  }
  printInstruction(MI);
  return true;
}

/// runOnMachineFunction - This uses the printInstruction()
/// method to print assembly for each instruction.
///
bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
  this->MF = &MF;

  // This calls the base class function required to be called at beginning
  // of runOnMachineFunction.
  SetupMachineFunction(MF);

  // Get the mangled name.
  const Function *F = MF.getFunction();
  CurrentFnName = Mang->getValueName(F);

  // Emit the function variables.
  emitFunctionData(MF);
  std::string codeSection;
  codeSection = "code." + CurrentFnName + ".# " + "CODE";
  const Section *fCodeSection = TAI->getNamedSection(codeSection.c_str(),
                                               SectionFlags::Code);
  O <<  "\n";
  SwitchToSection (fCodeSection);

  // Emit the frame address of the function at the beginning of code.
  O << "    retlw  low(" << FunctionLabelBegin<< CurrentFnName << ".frame)\n";
  O << "    retlw  high(" << FunctionLabelBegin<< CurrentFnName << ".frame)\n"; 
  O << CurrentFnName << ":\n";


  // Print out code for the function.
  for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
       I != E; ++I) {
    // Print a label for the basic block.
    if (I != MF.begin()) {
      printBasicBlockLabel(I, true);
      O << '\n';
    }
    CurBank = "";
    
    // For emitting line directives, we need to keep track of the current
    // source line. When it changes then only emit the line directive.
    unsigned CurLine = 0;
    for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
         II != E; ++II) {
      // Emit the line directive if source line changed.
      const DebugLoc DL = II->getDebugLoc();
      if (!DL.isUnknown()) {
        unsigned line = MF.getDebugLocTuple(DL).Line;
        if (line != CurLine) {
          O << "\t.line " << line << "\n";
          CurLine = line;
        }
      }
      // Print the assembly for the instruction.
      printMachineInstruction(II);
    }
  }
  return false;  // we didn't modify anything.
}

/// createPIC16CodePrinterPass - Returns a pass that prints the PIC16
/// assembly code for a MachineFunction to the given output stream,
/// using the given target machine description.  This should work
/// regardless of whether the function is in SSA form.
///
FunctionPass *llvm::createPIC16CodePrinterPass(raw_ostream &o,
                                               PIC16TargetMachine &tm,
                                               bool fast, bool verbose) {
  return new PIC16AsmPrinter(o, tm, tm.getTargetAsmInfo(), fast, verbose);
}

void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
  const MachineOperand &MO = MI->getOperand(opNum);

  switch (MO.getType()) {
    case MachineOperand::MO_Register:
      if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
        O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
      else
        assert(0 && "not implemented");
        return;

    case MachineOperand::MO_Immediate:
      O << (int)MO.getImm();
      return;

    case MachineOperand::MO_GlobalAddress: {
      std::string Name = Mang->getValueName(MO.getGlobal());
      if (isLocalName(Name)) 
        O << FunctionLabelBegin << Mang->getValueName(MO.getGlobal());
      else
         O << Mang->getValueName(MO.getGlobal());
      break;
    }
    case MachineOperand::MO_ExternalSymbol: {
      std::string Name = MO.getSymbolName(); 
      if (Name.find("__intrinsics.") != std::string::npos)
        O  << MO.getSymbolName();
      else
        O << FunctionLabelBegin << MO.getSymbolName();
      break;
    }
    case MachineOperand::MO_MachineBasicBlock:
      printBasicBlockLabel(MO.getMBB());
      return;

    default:
      assert(0 && " Operand type not supported.");
  }
}

void PIC16AsmPrinter::printCCOperand(const MachineInstr *MI, int opNum) {
  int CC = (int)MI->getOperand(opNum).getImm();
  O << PIC16CondCodeToString((PIC16CC::CondCodes)CC);
}


bool PIC16AsmPrinter::doInitialization (Module &M) {
  bool Result = AsmPrinter::doInitialization(M);
  // FIXME:: This is temporary solution to generate the include file.
  // The processor should be passed to llc as in input and the header file
  // should be generated accordingly.
  O << "\t#include P16F1937.INC\n";
  MachineModuleInfo *MMI = getAnalysisIfAvailable<MachineModuleInfo>();
  assert(MMI);
  DwarfWriter *DW = getAnalysisIfAvailable<DwarfWriter>();
  assert(DW && "Dwarf Writer is not available");
  DW->BeginModule(&M, MMI, O, this, TAI);

  EmitExternsAndGlobals (M);
  EmitInitData (M);
  EmitUnInitData(M);
  EmitRomData(M);
  return Result;
}

void PIC16AsmPrinter::EmitExternsAndGlobals (Module &M) {
 // Emit declarations for external functions.
  O << "section.0" <<"\n";
  for (Module::iterator I = M.begin(), E = M.end(); I != E; I++) {
    std::string Name = Mang->getValueName(I);
    if (Name.compare("abort") == 0)
      continue;
    
    // If it is llvm intrinsic call then don't emit
    if (Name.find("llvm.") != std::string::npos)
      continue;

    if (I->isDeclaration()) {
      O << "\textern " <<Name << "\n";
      O << "\textern "  << FunctionLabelBegin << Name << ".retval\n";
      O << "\textern " << FunctionLabelBegin << Name << ".args\n";
    }
    else if (I->hasExternalLinkage()) {
      O << "\tglobal " << Name << "\n";
      O << "\tglobal " << FunctionLabelBegin << Name << ".retval\n";
      O << "\tglobal " << FunctionLabelBegin<< Name << ".args\n";
    }
  }

  // Emit header file to include declaration of library functions
  O << "\t#include C16IntrinsicCalls.INC\n";

  // Emit declarations for external globals.
  for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
       I != E; I++) {
    // Any variables reaching here with ".auto." in its name is a local scope
    // variable and should not be printed in global data section.
    std::string Name = Mang->getValueName(I);
    if (isLocalName (Name))
      continue;

    if (I->isDeclaration())
      O << "\textern "<< Name << "\n";
    else if (I->hasCommonLinkage() || I->hasExternalLinkage())
      O << "\tglobal "<< Name << "\n";
  }
}

void PIC16AsmPrinter::EmitInitData (Module &M) {
  SwitchToSection(TAI->getDataSection());
  for (Module::global_iterator I = M.global_begin(), E = M.global_end();
       I != E; ++I) {
    if (!I->hasInitializer())   // External global require no code.
      continue;

    Constant *C = I->getInitializer();
    const PointerType *PtrTy = I->getType();
    int AddrSpace = PtrTy->getAddressSpace();

    if ((!C->isNullValue()) && (AddrSpace == PIC16ISD::RAM_SPACE)) {
    
      if (EmitSpecialLLVMGlobal(I)) 
        continue;

      // Any variables reaching here with "." in its name is a local scope
      // variable and should not be printed in global data section.
      std::string Name = Mang->getValueName(I);
      if (isLocalName(Name))
        continue;

      I->setSection(TAI->getDataSection()->getName());
      O << Name;
      EmitGlobalConstant(C, AddrSpace);
    }
  }
}

void PIC16AsmPrinter::EmitRomData (Module &M)
{
  SwitchToSection(TAI->getReadOnlySection());
  IsRomData = true;
  for (Module::global_iterator I = M.global_begin(), E = M.global_end();
       I != E; ++I) {
    if (!I->hasInitializer())   // External global require no code.
      continue;

    Constant *C = I->getInitializer();
    const PointerType *PtrTy = I->getType();
    int AddrSpace = PtrTy->getAddressSpace();
    if ((!C->isNullValue()) && (AddrSpace == PIC16ISD::ROM_SPACE)) {

      if (EmitSpecialLLVMGlobal(I))
        continue;

      // Any variables reaching here with "." in its name is a local scope
      // variable and should not be printed in global data section.
      std::string name = Mang->getValueName(I);
      if (name.find(".") != std::string::npos)
        continue;

      I->setSection(TAI->getReadOnlySection()->getName());
      O << name;
      EmitGlobalConstant(C, AddrSpace);
      O << "\n";
    }
  }
  IsRomData = false;
}

void PIC16AsmPrinter::EmitUnInitData (Module &M)
{
  SwitchToSection(TAI->getBSSSection_());
  const TargetData *TD = TM.getTargetData();

  for (Module::global_iterator I = M.global_begin(), E = M.global_end();
       I != E; ++I) {
    if (!I->hasInitializer())   // External global require no code.
      continue;

    Constant *C = I->getInitializer();
    if (C->isNullValue()) {

      if (EmitSpecialLLVMGlobal(I))
        continue;

      // Any variables reaching here with "." in its name is a local scope
      // variable and should not be printed in global data section.
      std::string name = Mang->getValueName(I);
      if (name.find(".") != std::string::npos)
        continue;

      I->setSection(TAI->getBSSSection_()->getName());

      const Type *Ty = C->getType();
      unsigned Size = TD->getTypePaddedSize(Ty);

      O << name << " " <<"RES"<< " " << Size ;
      O << "\n";
    }
  }
}

bool PIC16AsmPrinter::doFinalization(Module &M) {
  O << "\t" << "END\n";
  bool Result = AsmPrinter::doFinalization(M);
  return Result;
}

void PIC16AsmPrinter::emitFunctionData(MachineFunction &MF) {
  const Function *F = MF.getFunction();
  std::string FuncName = Mang->getValueName(F);
  Module *M = const_cast<Module *>(F->getParent());
  const TargetData *TD = TM.getTargetData();
  unsigned FrameSize = 0;
  // Emit the data section name.
  O << "\n"; 
  std::string SectionName = "fpdata." + CurrentFnName + ".# " + "UDATA_OVR";

  const Section *fPDataSection = TAI->getNamedSection(SectionName.c_str(),
                                                      SectionFlags::Writeable);
  SwitchToSection(fPDataSection);
  

  // Emit function frame label
  O << FunctionLabelBegin << CurrentFnName << ".frame:\n";

  const Type *RetType = F->getReturnType();
  unsigned RetSize = 0; 
  if (RetType->getTypeID() != Type::VoidTyID) 
    RetSize = TD->getTypePaddedSize(RetType);
  
  //Emit function return value space
  if(RetSize > 0)
     O << FunctionLabelBegin << CurrentFnName << ".retval    RES  " << RetSize 
       << "\n";
  else
     O << FunctionLabelBegin << CurrentFnName << ".retval:\n";
   
  // Emit variable to hold the space for function arguments 
  unsigned ArgSize = 0;
  for (Function::const_arg_iterator argi = F->arg_begin(),
           arge = F->arg_end(); argi != arge ; ++argi) {
    const Type *Ty = argi->getType();
    ArgSize += TD->getTypePaddedSize(Ty);
   }
  O << FunctionLabelBegin << CurrentFnName << ".args      RES  " << ArgSize 
    << "\n";

  // Emit temporary space
  int TempSize = PTLI->GetTmpSize();
  if (TempSize > 0 )
    O << FunctionLabelBegin << CurrentFnName << ".tmp       RES  " << TempSize 
      <<"\n";

  // Emit the section name for local variables.
  O << "\n";
  std::string SecNameLocals = "fadata." + CurrentFnName + ".# " + "UDATA_OVR";

  const Section *fADataSection = TAI->getNamedSection(SecNameLocals.c_str(),
                                                      SectionFlags::Writeable);
  SwitchToSection(fADataSection);

  // Emit the function variables. 
   
  // In PIC16 all the function arguments and local variables are global.
  // Therefore to get the variable belonging to this function entire
  // global list will be traversed and variables belonging to this function
  // will be emitted in the current data section.
  for (Module::global_iterator I = M->global_begin(), E = M->global_end();
       I != E; ++I) {
    std::string VarName = Mang->getValueName(I);
    
    // The variables of a function are of form FuncName.* . If this variable
    // does not belong to this function then continue. 
    // Static local varilabes of a function does not have .auto. in their
    // name. They are not printed as part of function data but module
    // level global data.
    if (! isLocalToFunc(FuncName, VarName))
     continue;

    I->setSection("fadata." + CurrentFnName + ".#");
    Constant *C = I->getInitializer();
    const Type *Ty = C->getType();
    unsigned Size = TD->getTypePaddedSize(Ty);
    FrameSize += Size; 
    // Emit memory reserve directive.
    O << FunctionLabelBegin << VarName << "  RES  " << Size << "\n";
  }

}