1//===-- Thumb2SizeReduction.cpp - Thumb2 code size reduction pass -*- C++ -*-=//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
--- 91 unchanged lines hidden (view full) ---
100 { ARM::t2SXTBr, ARM::tSXTB, 0, 0, 0, 1, 0, 1,0, 0 },
101 { ARM::t2SXTHr, ARM::tSXTH, 0, 0, 0, 1, 0, 1,0, 0 },
102 { ARM::t2TSTrr, ARM::tTST, 0, 0, 0, 1, 0, 2,0, 0 },
103 { ARM::t2UXTBr, ARM::tUXTB, 0, 0, 0, 1, 0, 1,0, 0 },
104 { ARM::t2UXTHr, ARM::tUXTH, 0, 0, 0, 1, 0, 1,0, 0 },
105
106 // FIXME: Clean this up after splitting each Thumb load / store opcode
107 // into multiple ones.
108 { ARM::t2LDRi12,ARM::tLDR, ARM::tLDRspi, 5, 8, 1, 0, 0,0, 1 },
109 { ARM::t2LDRs, ARM::tLDR, 0, 0, 0, 1, 0, 0,0, 1 },
110 { ARM::t2LDRBi12,ARM::tLDRB, 0, 5, 0, 1, 0, 0,0, 1 },
111 { ARM::t2LDRBs, ARM::tLDRB, 0, 0, 0, 1, 0, 0,0, 1 },
112 { ARM::t2LDRHi12,ARM::tLDRH, 0, 5, 0, 1, 0, 0,0, 1 },
113 { ARM::t2LDRHs, ARM::tLDRH, 0, 0, 0, 1, 0, 0,0, 1 },
114 { ARM::t2LDRSBs,ARM::tLDRSB, 0, 0, 0, 1, 0, 0,0, 1 },
115 { ARM::t2LDRSHs,ARM::tLDRSH, 0, 0, 0, 1, 0, 0,0, 1 },
116 { ARM::t2STRi12,ARM::tSTR, ARM::tSTRspi, 5, 8, 1, 0, 0,0, 1 },
117 { ARM::t2STRs, ARM::tSTR, 0, 0, 0, 1, 0, 0,0, 1 },
118 { ARM::t2STRBi12,ARM::tSTRB, 0, 5, 0, 1, 0, 0,0, 1 },
119 { ARM::t2STRBs, ARM::tSTRB, 0, 0, 0, 1, 0, 0,0, 1 },
120 { ARM::t2STRHi12,ARM::tSTRH, 0, 5, 0, 1, 0, 0,0, 1 },
121 { ARM::t2STRHs, ARM::tSTRH, 0, 0, 0, 1, 0, 0,0, 1 },
122
123 { ARM::t2LDM_RET,0, ARM::tPOP_RET, 0, 0, 1, 1, 1,1, 1 },
124 { ARM::t2LDM, ARM::tLDM, ARM::tPOP, 0, 0, 1, 1, 1,1, 1 },
--- 114 unchanged lines hidden (view full) ---
239 continue;
240 unsigned Reg = MO.getReg();
241 if (Reg == 0 || Reg == ARM::CPSR)
242 continue;
243 if (isPCOk && Reg == ARM::PC)
244 continue;
245 if (isLROk && Reg == ARM::LR)
246 continue;
247 if (Reg == ARM::SP) {
248 if (isSPOk)
249 continue;
250 if (i == 1 && (Opc == ARM::t2LDRi12 || Opc == ARM::t2STRi12))
251 // Special case for these ldr / str with sp as base register.
252 continue;
253 }
254 if (!isARMLowRegister(Reg))
255 return false;
256 }
257 return true;
258}
259
260bool
261Thumb2SizeReduce::ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI,
262 const ReduceEntry &Entry) {
263 if (ReduceLimitLdSt != -1 && ((int)NumLdSts >= ReduceLimitLdSt))
264 return false;
265
266 unsigned Scale = 1;
267 bool HasImmOffset = false;
268 bool HasShift = false;
269 bool HasOffReg = true;
270 bool isLdStMul = false;
271 unsigned Opc = Entry.NarrowOpc1;
272 unsigned OpNum = 3; // First 'rest' of operands.
273 uint8_t ImmLimit = Entry.Imm1Limit;
274 switch (Entry.WideOpc) {
275 default:
276 llvm_unreachable("Unexpected Thumb2 load / store opcode!");
277 case ARM::t2LDRi12:
278 case ARM::t2STRi12: {
279 unsigned BaseReg = MI->getOperand(1).getReg();
280 if (BaseReg == ARM::SP) {
281 Opc = Entry.NarrowOpc2;
282 ImmLimit = Entry.Imm2Limit;
283 HasOffReg = false;
284 }
285 Scale = 4;
286 HasImmOffset = true;
287 break;
288 }
289 case ARM::t2LDRBi12:
290 case ARM::t2STRBi12:
291 HasImmOffset = true;
292 break;
293 case ARM::t2LDRHi12:
294 case ARM::t2STRHi12:
295 Scale = 2;
296 HasImmOffset = true;
--- 37 unchanged lines hidden (view full) ---
334 if (MI->getOperand(3).getImm())
335 // Thumb1 addressing mode doesn't support shift.
336 return false;
337 }
338
339 unsigned OffsetImm = 0;
340 if (HasImmOffset) {
341 OffsetImm = MI->getOperand(2).getImm();
342 unsigned MaxOffset = ((1 << ImmLimit) - 1) * Scale;
343 if ((OffsetImm & (Scale-1)) || OffsetImm > MaxOffset)
344 // Make sure the immediate field fits.
345 return false;
346 }
347
348 // Add the 16-bit load / store instruction.
349 // FIXME: Thumb1 addressing mode encode both immediate and register offset.
350 DebugLoc dl = MI->getDebugLoc();
351 MachineInstrBuilder MIB = BuildMI(MBB, *MI, dl, TII->get(Opc));
352 if (!isLdStMul) {
353 MIB.addOperand(MI->getOperand(0)).addOperand(MI->getOperand(1));
354 if (Opc != ARM::tLDRSB && Opc != ARM::tLDRSH) {
355 // tLDRSB and tLDRSH do not have an immediate offset field. On the other
356 // hand, it must have an offset register.
357 // FIXME: Remove this special case.
358 MIB.addImm(OffsetImm/Scale);
359 }
360 assert((!HasShift || OffsetReg) && "Invalid so_reg load / store address!");
361
362 if (HasOffReg)
363 MIB.addReg(OffsetReg, getKillRegState(OffsetKill));
364 }
365
366 // Transfer the rest of operands.
367 for (unsigned e = MI->getNumOperands(); OpNum != e; ++OpNum)
368 MIB.addOperand(MI->getOperand(OpNum));
369
370 // Transfer memoperands.
371 (*MIB).setMemRefs(MI->memoperands_begin(), MI->memoperands_end());
372
373 DEBUG(errs() << "Converted 32-bit: " << *MI << " to 16-bit: " << *MIB);
374
375 MBB.erase(MI);
376 ++NumLdSts;
377 return true;
378}
379
380bool
--- 322 unchanged lines hidden ---
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
--- 91 unchanged lines hidden (view full) ---
100 { ARM::t2SXTBr, ARM::tSXTB, 0, 0, 0, 1, 0, 1,0, 0 },
101 { ARM::t2SXTHr, ARM::tSXTH, 0, 0, 0, 1, 0, 1,0, 0 },
102 { ARM::t2TSTrr, ARM::tTST, 0, 0, 0, 1, 0, 2,0, 0 },
103 { ARM::t2UXTBr, ARM::tUXTB, 0, 0, 0, 1, 0, 1,0, 0 },
104 { ARM::t2UXTHr, ARM::tUXTH, 0, 0, 0, 1, 0, 1,0, 0 },
105
106 // FIXME: Clean this up after splitting each Thumb load / store opcode
107 // into multiple ones.
108 { ARM::t2LDRi12,ARM::tLDR, ARM::tLDRspi, 5, 8, 1, 0, 0,0, 1 },
109 { ARM::t2LDRs, ARM::tLDR, 0, 0, 0, 1, 0, 0,0, 1 },
110 { ARM::t2LDRBi12,ARM::tLDRB, 0, 5, 0, 1, 0, 0,0, 1 },
111 { ARM::t2LDRBs, ARM::tLDRB, 0, 0, 0, 1, 0, 0,0, 1 },
112 { ARM::t2LDRHi12,ARM::tLDRH, 0, 5, 0, 1, 0, 0,0, 1 },
113 { ARM::t2LDRHs, ARM::tLDRH, 0, 0, 0, 1, 0, 0,0, 1 },
114 { ARM::t2LDRSBs,ARM::tLDRSB, 0, 0, 0, 1, 0, 0,0, 1 },
115 { ARM::t2LDRSHs,ARM::tLDRSH, 0, 0, 0, 1, 0, 0,0, 1 },
116 { ARM::t2STRi12,ARM::tSTR, ARM::tSTRspi, 5, 8, 1, 0, 0,0, 1 },
117 { ARM::t2STRs, ARM::tSTR, 0, 0, 0, 1, 0, 0,0, 1 },
118 { ARM::t2STRBi12,ARM::tSTRB, 0, 5, 0, 1, 0, 0,0, 1 },
119 { ARM::t2STRBs, ARM::tSTRB, 0, 0, 0, 1, 0, 0,0, 1 },
120 { ARM::t2STRHi12,ARM::tSTRH, 0, 5, 0, 1, 0, 0,0, 1 },
121 { ARM::t2STRHs, ARM::tSTRH, 0, 0, 0, 1, 0, 0,0, 1 },
122
123 { ARM::t2LDM_RET,0, ARM::tPOP_RET, 0, 0, 1, 1, 1,1, 1 },
124 { ARM::t2LDM, ARM::tLDM, ARM::tPOP, 0, 0, 1, 1, 1,1, 1 },
--- 114 unchanged lines hidden (view full) ---
239 continue;
240 unsigned Reg = MO.getReg();
241 if (Reg == 0 || Reg == ARM::CPSR)
242 continue;
243 if (isPCOk && Reg == ARM::PC)
244 continue;
245 if (isLROk && Reg == ARM::LR)
246 continue;
247 if (Reg == ARM::SP) {
248 if (isSPOk)
249 continue;
250 if (i == 1 && (Opc == ARM::t2LDRi12 || Opc == ARM::t2STRi12))
251 // Special case for these ldr / str with sp as base register.
252 continue;
253 }
254 if (!isARMLowRegister(Reg))
255 return false;
256 }
257 return true;
258}
259
260bool
261Thumb2SizeReduce::ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI,
262 const ReduceEntry &Entry) {
263 if (ReduceLimitLdSt != -1 && ((int)NumLdSts >= ReduceLimitLdSt))
264 return false;
265
266 unsigned Scale = 1;
267 bool HasImmOffset = false;
268 bool HasShift = false;
269 bool HasOffReg = true;
270 bool isLdStMul = false;
271 unsigned Opc = Entry.NarrowOpc1;
272 unsigned OpNum = 3; // First 'rest' of operands.
273 uint8_t ImmLimit = Entry.Imm1Limit;
274 switch (Entry.WideOpc) {
275 default:
276 llvm_unreachable("Unexpected Thumb2 load / store opcode!");
277 case ARM::t2LDRi12:
278 case ARM::t2STRi12: {
279 unsigned BaseReg = MI->getOperand(1).getReg();
280 if (BaseReg == ARM::SP) {
281 Opc = Entry.NarrowOpc2;
282 ImmLimit = Entry.Imm2Limit;
283 HasOffReg = false;
284 }
285 Scale = 4;
286 HasImmOffset = true;
287 break;
288 }
289 case ARM::t2LDRBi12:
290 case ARM::t2STRBi12:
291 HasImmOffset = true;
292 break;
293 case ARM::t2LDRHi12:
294 case ARM::t2STRHi12:
295 Scale = 2;
296 HasImmOffset = true;
--- 37 unchanged lines hidden (view full) ---
334 if (MI->getOperand(3).getImm())
335 // Thumb1 addressing mode doesn't support shift.
336 return false;
337 }
338
339 unsigned OffsetImm = 0;
340 if (HasImmOffset) {
341 OffsetImm = MI->getOperand(2).getImm();
342 unsigned MaxOffset = ((1 << ImmLimit) - 1) * Scale;
343 if ((OffsetImm & (Scale-1)) || OffsetImm > MaxOffset)
344 // Make sure the immediate field fits.
345 return false;
346 }
347
348 // Add the 16-bit load / store instruction.
349 // FIXME: Thumb1 addressing mode encode both immediate and register offset.
350 DebugLoc dl = MI->getDebugLoc();
351 MachineInstrBuilder MIB = BuildMI(MBB, *MI, dl, TII->get(Opc));
352 if (!isLdStMul) {
353 MIB.addOperand(MI->getOperand(0)).addOperand(MI->getOperand(1));
354 if (Opc != ARM::tLDRSB && Opc != ARM::tLDRSH) {
355 // tLDRSB and tLDRSH do not have an immediate offset field. On the other
356 // hand, it must have an offset register.
357 // FIXME: Remove this special case.
358 MIB.addImm(OffsetImm/Scale);
359 }
360 assert((!HasShift || OffsetReg) && "Invalid so_reg load / store address!");
361
362 if (HasOffReg)
363 MIB.addReg(OffsetReg, getKillRegState(OffsetKill));
364 }
365
366 // Transfer the rest of operands.
367 for (unsigned e = MI->getNumOperands(); OpNum != e; ++OpNum)
368 MIB.addOperand(MI->getOperand(OpNum));
369
370 // Transfer memoperands.
371 (*MIB).setMemRefs(MI->memoperands_begin(), MI->memoperands_end());
372
373 DEBUG(errs() << "Converted 32-bit: " << *MI << " to 16-bit: " << *MIB);
374
375 MBB.erase(MI);
376 ++NumLdSts;
377 return true;
378}
379
380bool
--- 322 unchanged lines hidden ---