aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target/PIC16/PIC16AsmPrinter.cpp
blob: 63ad6e4f4488b1a0f4810a84439ed378bf3355a2 (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
//===-- 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/Support/raw_ostream.h"
#include "llvm/Support/Mangler.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/DerivedTypes.h"

using namespace llvm;

#include "PIC16GenAsmWriter.inc"
bool PIC16AsmPrinter::inSameBank (char *s1, char *s2){

  assert (s1 && s2 && "Null pointer assignment");

  if ((*s1 == '.') && (*s2 == '.')) { //skip if they both start with '.'
    s1++;
    s2++;
  }
  while (*s1 && *s2) {
    if (*s1 != *s2) 
      goto _NotInSameBank;

    if ((*s1 == '.') && (*s2 == '.')) //both symbols in same function
      goto _InSameBank;               //in the same bank

    s1++;
    s2++;
  }

  if (*s1 && *s1) {
  _InSameBank:
    return true;
  }

 _NotInSameBank:
  return false;
}

bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
  std::string NewBankselLabel;
  unsigned Operands = MI->getNumOperands();
  if (Operands > 1) {
    // Global address or external symbol should be second operand from last
    // if we want to print banksel for it.
    const MachineOperand &Op = MI->getOperand(Operands-2);
    unsigned OpType = Op.getType();
    if (OpType == MachineOperand::MO_GlobalAddress ||
        OpType == MachineOperand::MO_ExternalSymbol) { 
      if (OpType == MachineOperand::MO_GlobalAddress ) 
        NewBankselLabel =  Mang->getValueName(Op.getGlobal());
      else 
        NewBankselLabel =  Op.getSymbolName();

      // 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(Operands-1);
      if (((int)BS.getImm() == 1) &&
          (!inSameBank ((char *)CurrentBankselLabelInBasicBlock.c_str(),
			(char *)NewBankselLabel.c_str()))) {
        CurrentBankselLabelInBasicBlock = NewBankselLabel;
        O << "\tbanksel ";
        printOperand(MI, Operands-2);
        O << "\n";
      }
    }
  }
  printInstruction(MI);
  return true;
}

/// runOnMachineFunction - This uses the printInstruction()
/// method to print assembly for each instruction.
///
bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &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);

  // 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';
    }
    else
      O << CurrentFnName << ":\n";
    CurrentBankselLabelInBasicBlock = "";
    for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
         II != E; ++II) {
      // 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) {
  return new PIC16AsmPrinter(o, tm, tm.getTargetAsmInfo());
}

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:
      O << Mang->getValueName(MO.getGlobal());
      break;

    case MachineOperand::MO_ExternalSymbol:
      O << 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";
  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 (I->isDeclaration()) {
      O << "\textern " <<Name << "\n";
      O << "\textern " << Name << ".retval\n";
      O << "\textern " << Name << ".args\n";
    }
    else if (I->hasExternalLinkage()) {
      O << "\tglobal " << Name << "\n";
      O << "\tglobal " << Name << ".retval\n";
      O << "\tglobal " << 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++) {
    std::string Name = Mang->getValueName(I);
    if (I->isDeclaration())
      O << "\textern "<< Name << "\n";
    else if (I->getLinkage() == GlobalValue::CommonLinkage)
      O << "\tglobal "<< Name << "\n";
  }
}
void PIC16AsmPrinter::EmitInitData (Module &M) {
  SwitchToSection(TAI->getDataSection());
  for (Module::const_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 (name.find(".") != std::string::npos)
        continue;

      O << name;
      EmitGlobalConstant(C, AddrSpace);
    }
  }
}

void PIC16AsmPrinter::EmitRomData (Module &M)
{
  SwitchToSection(TAI->getReadOnlySection());
  IsRomData = true;
  for (Module::const_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;

      O << name;
      EmitGlobalConstant(C, AddrSpace);
      O << "\n";
    }
  }
  IsRomData = false;
}

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

  for (Module::const_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;

      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);
  const Module *M = F->getParent();
  const TargetData *TD = TM.getTargetData();
  unsigned FrameSize = 0;
  // Emit the data section name.
  O << "\n"; 
  std::string SectionName = "fdata." + CurrentFnName + ".# " + "UDATA";

  const Section *fDataSection = TAI->getNamedSection(SectionName.c_str(),
                                               SectionFlags::Writeable);
  SwitchToSection(fDataSection);
  
  //Emit function return value.
  O << CurrentFnName << ".retval:\n";
  const Type *RetType = F->getReturnType();
  unsigned RetSize = 0; 
  if (RetType->getTypeID() != Type::VoidTyID) 
    RetSize = TD->getTypePaddedSize(RetType);
  
  // Emit function arguments.
  O << CurrentFnName << ".args:\n";
  // 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::const_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. 
    if (!(VarName.find(FuncName + ".") == 0 ? true : false))
      continue;
   
    Constant *C = I->getInitializer();
    const Type *Ty = C->getType();
    unsigned Size = TD->getTypePaddedSize(Ty);
    FrameSize += Size; 
    // Emit memory reserve directive.
    O << VarName << "  RES  " << Size << "\n";
  }
  emitFunctionTempData(MF, FrameSize);
  if (RetSize > FrameSize)
    O << CurrentFnName << ".dummy" << "RES" << (RetSize - FrameSize); 
}

void PIC16AsmPrinter::emitFunctionTempData(MachineFunction &MF,
                                           unsigned &FrameSize) {
  // Emit temporary variables.
  MachineFrameInfo *FrameInfo = MF.getFrameInfo();
  if (FrameInfo->hasStackObjects()) {
    int indexBegin = FrameInfo->getObjectIndexBegin();
    int indexEnd = FrameInfo->getObjectIndexEnd();

    if (indexBegin < indexEnd) { 
      FrameSize += indexEnd - indexBegin; 
      O << CurrentFnName << ".tmp RES"<< " " 
        <<indexEnd - indexBegin <<"\n";
    } 
    /*
    while (indexBegin < indexEnd) {
        O << CurrentFnName << "_tmp_" << indexBegin << " " << "RES"<< " " 
          << 1 << "\n" ;
        indexBegin++;
    }
    */
  }
}