@@ -52,6 +52,8 @@ class AVRExpandPseudo : public MachineFunctionPass {
52
52
53
53
// / The register to be used for temporary storage.
54
54
const unsigned SCRATCH_REGISTER = AVR::R0;
55
+ // / The register that will always contain zero.
56
+ const unsigned ZERO_REGISTER = AVR::R1;
55
57
// / The IO address of the status register.
56
58
const unsigned SREG_ADDR = 0x3f ;
57
59
@@ -1242,6 +1244,93 @@ bool AVRExpandPseudo::expand<AVR::POPWRd>(Block &MBB, BlockIt MBBI) {
1242
1244
return true ;
1243
1245
}
1244
1246
1247
+ template <>
1248
+ bool AVRExpandPseudo::expand<AVR::ROLBRd>(Block &MBB, BlockIt MBBI) {
1249
+ // In AVR, the rotate instructions behave quite unintuitively. They rotate
1250
+ // bits through the carry bit in SREG, effectively rotating over 9 bits,
1251
+ // instead of 8. This is useful when we are dealing with numbers over
1252
+ // multiple registers, but when we actually need to rotate stuff, we have
1253
+ // to explicitly add the carry bit.
1254
+
1255
+ MachineInstr &MI = *MBBI;
1256
+ unsigned OpShift, OpCarry;
1257
+ unsigned DstReg = MI.getOperand (0 ).getReg ();
1258
+ bool DstIsDead = MI.getOperand (0 ).isDead ();
1259
+ OpShift = AVR::ADDRdRr;
1260
+ OpCarry = AVR::ADCRdRr;
1261
+
1262
+ // add r16, r16
1263
+ // adc r16, r1
1264
+
1265
+ // Shift part
1266
+ buildMI (MBB, MBBI, OpShift)
1267
+ .addReg (DstReg, RegState::Define | getDeadRegState (DstIsDead))
1268
+ .addReg (DstReg)
1269
+ .addReg (DstReg);
1270
+
1271
+ // Add the carry bit
1272
+ auto MIB = buildMI (MBB, MBBI, OpCarry)
1273
+ .addReg (DstReg, RegState::Define | getDeadRegState (DstIsDead))
1274
+ .addReg (DstReg)
1275
+ .addReg (ZERO_REGISTER);
1276
+
1277
+ // SREG is always implicitly killed
1278
+ MIB->getOperand (2 ).setIsKill ();
1279
+
1280
+ MI.eraseFromParent ();
1281
+ return true ;
1282
+ }
1283
+
1284
+ template <>
1285
+ bool AVRExpandPseudo::expand<AVR::RORBRd>(Block &MBB, BlockIt MBBI) {
1286
+ // In AVR, the rotate instructions behave quite unintuitively. They rotate
1287
+ // bits through the carry bit in SREG, effectively rotating over 9 bits,
1288
+ // instead of 8. This is useful when we are dealing with numbers over
1289
+ // multiple registers, but when we actually need to rotate stuff, we have
1290
+ // to explicitly add the carry bit.
1291
+
1292
+ MachineInstr &MI = *MBBI;
1293
+ unsigned OpShiftOut, OpLoad, OpShiftIn, OpAdd;
1294
+ unsigned DstReg = MI.getOperand (0 ).getReg ();
1295
+ bool DstIsDead = MI.getOperand (0 ).isDead ();
1296
+ OpShiftOut = AVR::LSRRd;
1297
+ OpLoad = AVR::LDIRdK;
1298
+ OpShiftIn = AVR::RORRd;
1299
+ OpAdd = AVR::ORRdRr;
1300
+
1301
+ // lsr r16
1302
+ // ldi r0, 0
1303
+ // ror r0
1304
+ // or r16, r17
1305
+
1306
+ // Shift out
1307
+ buildMI (MBB, MBBI, OpShiftOut)
1308
+ .addReg (DstReg, RegState::Define | getDeadRegState (DstIsDead))
1309
+ .addReg (DstReg);
1310
+
1311
+ // Put 0 in temporary register
1312
+ buildMI (MBB, MBBI, OpLoad)
1313
+ .addReg (SCRATCH_REGISTER, RegState::Define | getDeadRegState (true ))
1314
+ .addImm (0x00 );
1315
+
1316
+ // Shift in
1317
+ buildMI (MBB, MBBI, OpShiftIn)
1318
+ .addReg (SCRATCH_REGISTER, RegState::Define | getDeadRegState (true ))
1319
+ .addReg (SCRATCH_REGISTER);
1320
+
1321
+ // Add the results together using an or-instruction
1322
+ auto MIB = buildMI (MBB, MBBI, OpAdd)
1323
+ .addReg (DstReg, RegState::Define | getDeadRegState (DstIsDead))
1324
+ .addReg (DstReg)
1325
+ .addReg (SCRATCH_REGISTER);
1326
+
1327
+ // SREG is always implicitly killed
1328
+ MIB->getOperand (2 ).setIsKill ();
1329
+
1330
+ MI.eraseFromParent ();
1331
+ return true ;
1332
+ }
1333
+
1245
1334
template <>
1246
1335
bool AVRExpandPseudo::expand<AVR::LSLWRd>(Block &MBB, BlockIt MBBI) {
1247
1336
MachineInstr &MI = *MBBI;
@@ -1562,6 +1651,8 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
1562
1651
EXPAND (AVR::OUTWARr);
1563
1652
EXPAND (AVR::PUSHWRr);
1564
1653
EXPAND (AVR::POPWRd);
1654
+ EXPAND (AVR::ROLBRd);
1655
+ EXPAND (AVR::RORBRd);
1565
1656
EXPAND (AVR::LSLWRd);
1566
1657
EXPAND (AVR::LSRWRd);
1567
1658
EXPAND (AVR::RORWRd);
0 commit comments