Skip to content

Commit 9a46e28

Browse files
Patryk27nikic
authored andcommitted
[AVR] Always expand STDSPQRr & STDWSPQRr
Currently, STDSPQRr and STDWSPQRr are expanded only during AVRFrameLowering - this means that if any of those instructions happen to appear _outside_ of the typical FrameSetup / FrameDestroy context, they wouldn't get substituted, eventually leading to a crash: ``` LLVM ERROR: Not supported instr: <MCInst XXX <MCOperand Reg:1> <MCOperand Imm:15> <MCOperand Reg:53>> ``` This commit fixes this issue by moving expansion of those two opcodes into AVRExpandPseudo. This bug was originally discovered due to the Rust compiler_builtins library. Its 0.1.37 release contained a 128-bit software division/remainder routine that exercised this buggy branch in the code. Reviewed By: benshi001 Differential Revision: https://reviews.llvm.org/D123528
1 parent 31ca698 commit 9a46e28

File tree

3 files changed

+109
-59
lines changed

3 files changed

+109
-59
lines changed

llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -1280,6 +1280,42 @@ bool AVRExpandPseudo::expand<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) {
12801280
return true;
12811281
}
12821282

1283+
template <>
1284+
bool AVRExpandPseudo::expand<AVR::STDSPQRr>(Block &MBB, BlockIt MBBI) {
1285+
MachineInstr &MI = *MBBI;
1286+
const MachineFunction &MF = *MBB.getParent();
1287+
const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
1288+
1289+
assert(MI.getOperand(0).getReg() == AVR::SP &&
1290+
"SP is expected as base pointer");
1291+
1292+
assert(STI.getFrameLowering()->hasReservedCallFrame(MF) &&
1293+
"unexpected STDSPQRr pseudo instruction");
1294+
1295+
MI.setDesc(TII->get(AVR::STDPtrQRr));
1296+
MI.getOperand(0).setReg(AVR::R29R28);
1297+
1298+
return true;
1299+
}
1300+
1301+
template <>
1302+
bool AVRExpandPseudo::expand<AVR::STDWSPQRr>(Block &MBB, BlockIt MBBI) {
1303+
MachineInstr &MI = *MBBI;
1304+
const MachineFunction &MF = *MBB.getParent();
1305+
const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
1306+
1307+
assert(MI.getOperand(0).getReg() == AVR::SP &&
1308+
"SP is expected as base pointer");
1309+
1310+
assert(STI.getFrameLowering()->hasReservedCallFrame(MF) &&
1311+
"unexpected STDWSPQRr pseudo instruction");
1312+
1313+
MI.setDesc(TII->get(AVR::STDWPtrQRr));
1314+
MI.getOperand(0).setReg(AVR::R29R28);
1315+
1316+
return true;
1317+
}
1318+
12831319
template <>
12841320
bool AVRExpandPseudo::expand<AVR::INWRdA>(Block &MBB, BlockIt MBBI) {
12851321
MachineInstr &MI = *MBBI;
@@ -2365,6 +2401,8 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
23652401
EXPAND(AVR::STWPtrPiRr);
23662402
EXPAND(AVR::STWPtrPdRr);
23672403
EXPAND(AVR::STDWPtrQRr);
2404+
EXPAND(AVR::STDSPQRr);
2405+
EXPAND(AVR::STDWSPQRr);
23682406
EXPAND(AVR::INWRdA);
23692407
EXPAND(AVR::OUTWARr);
23702408
EXPAND(AVR::PUSHWRr);

llvm/lib/Target/AVR/AVRFrameLowering.cpp

+56-59
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,8 @@ void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
201201

202202
// Restore the frame pointer by doing FP += <size>.
203203
MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)
204-
.addReg(AVR::R29R28, RegState::Kill)
205-
.addImm(FrameSize);
204+
.addReg(AVR::R29R28, RegState::Kill)
205+
.addImm(FrameSize);
206206
// The SREG implicit def is dead.
207207
MI->getOperand(3).setIsDead();
208208
}
@@ -299,7 +299,7 @@ bool AVRFrameLowering::restoreCalleeSavedRegisters(
299299
/// real instructions.
300300
static void fixStackStores(MachineBasicBlock &MBB,
301301
MachineBasicBlock::iterator StartMI,
302-
const TargetInstrInfo &TII, Register FP) {
302+
const TargetInstrInfo &TII) {
303303
// Iterate through the BB until we hit a call instruction or we reach the end.
304304
for (MachineInstr &MI :
305305
llvm::make_early_inc_range(llvm::make_range(StartMI, MBB.end()))) {
@@ -313,15 +313,15 @@ static void fixStackStores(MachineBasicBlock &MBB,
313313
continue;
314314

315315
assert(MI.getOperand(0).getReg() == AVR::SP &&
316-
"Invalid register, should be SP!");
316+
"SP is expected as base pointer");
317317

318318
// Replace this instruction with a regular store. Use Y as the base
319319
// pointer since it is guaranteed to contain a copy of SP.
320320
unsigned STOpc =
321321
(Opcode == AVR::STDWSPQRr) ? AVR::STDWPtrQRr : AVR::STDPtrQRr;
322322

323323
MI.setDesc(TII.get(STOpc));
324-
MI.getOperand(0).setReg(FP);
324+
MI.getOperand(0).setReg(AVR::R31R30);
325325
}
326326
}
327327

@@ -331,69 +331,66 @@ MachineBasicBlock::iterator AVRFrameLowering::eliminateCallFramePseudoInstr(
331331
const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
332332
const AVRInstrInfo &TII = *STI.getInstrInfo();
333333

334-
// There is nothing to insert when the call frame memory is allocated during
335-
// function entry. Delete the call frame pseudo and replace all pseudo stores
336-
// with real store instructions.
337334
if (hasReservedCallFrame(MF)) {
338-
fixStackStores(MBB, MI, TII, AVR::R29R28);
339335
return MBB.erase(MI);
340336
}
341337

342338
DebugLoc DL = MI->getDebugLoc();
343339
unsigned int Opcode = MI->getOpcode();
344340
int Amount = TII.getFrameSize(*MI);
345341

346-
// ADJCALLSTACKUP and ADJCALLSTACKDOWN are converted to adiw/subi
347-
// instructions to read and write the stack pointer in I/O space.
348-
if (Amount != 0) {
349-
assert(getStackAlign() == Align(1) && "Unsupported stack alignment");
350-
351-
if (Opcode == TII.getCallFrameSetupOpcode()) {
352-
// Update the stack pointer.
353-
// In many cases this can be done far more efficiently by pushing the
354-
// relevant values directly to the stack. However, doing that correctly
355-
// (in the right order, possibly skipping some empty space for undef
356-
// values, etc) is tricky and thus left to be optimized in the future.
357-
BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);
358-
359-
MachineInstr *New =
360-
BuildMI(MBB, MI, DL, TII.get(AVR::SUBIWRdK), AVR::R31R30)
361-
.addReg(AVR::R31R30, RegState::Kill)
362-
.addImm(Amount);
363-
New->getOperand(3).setIsDead();
364-
365-
BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP).addReg(AVR::R31R30);
366-
367-
// Make sure the remaining stack stores are converted to real store
368-
// instructions.
369-
fixStackStores(MBB, MI, TII, AVR::R31R30);
370-
} else {
371-
assert(Opcode == TII.getCallFrameDestroyOpcode());
372-
373-
// Note that small stack changes could be implemented more efficiently
374-
// with a few pop instructions instead of the 8-9 instructions now
375-
// required.
376-
377-
// Select the best opcode to adjust SP based on the offset size.
378-
unsigned addOpcode;
379-
if (isUInt<6>(Amount)) {
380-
addOpcode = AVR::ADIWRdK;
381-
} else {
382-
addOpcode = AVR::SUBIWRdK;
383-
Amount = -Amount;
384-
}
342+
if (Amount == 0) {
343+
return MBB.erase(MI);
344+
}
345+
346+
assert(getStackAlign() == Align(1) && "Unsupported stack alignment");
347+
348+
if (Opcode == TII.getCallFrameSetupOpcode()) {
349+
// Update the stack pointer.
350+
// In many cases this can be done far more efficiently by pushing the
351+
// relevant values directly to the stack. However, doing that correctly
352+
// (in the right order, possibly skipping some empty space for undef
353+
// values, etc) is tricky and thus left to be optimized in the future.
354+
BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);
355+
356+
MachineInstr *New =
357+
BuildMI(MBB, MI, DL, TII.get(AVR::SUBIWRdK), AVR::R31R30)
358+
.addReg(AVR::R31R30, RegState::Kill)
359+
.addImm(Amount);
360+
New->getOperand(3).setIsDead();
385361

386-
// Build the instruction sequence.
387-
BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);
362+
BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP).addReg(AVR::R31R30);
388363

389-
MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(addOpcode), AVR::R31R30)
390-
.addReg(AVR::R31R30, RegState::Kill)
391-
.addImm(Amount);
392-
New->getOperand(3).setIsDead();
364+
// Make sure the remaining stack stores are converted to real store
365+
// instructions.
366+
fixStackStores(MBB, MI, TII);
367+
} else {
368+
assert(Opcode == TII.getCallFrameDestroyOpcode());
393369

394-
BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP)
395-
.addReg(AVR::R31R30, RegState::Kill);
370+
// Note that small stack changes could be implemented more efficiently
371+
// with a few pop instructions instead of the 8-9 instructions now
372+
// required.
373+
374+
// Select the best opcode to adjust SP based on the offset size.
375+
unsigned AddOpcode;
376+
377+
if (isUInt<6>(Amount)) {
378+
AddOpcode = AVR::ADIWRdK;
379+
} else {
380+
AddOpcode = AVR::SUBIWRdK;
381+
Amount = -Amount;
396382
}
383+
384+
// Build the instruction sequence.
385+
BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);
386+
387+
MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(AddOpcode), AVR::R31R30)
388+
.addReg(AVR::R31R30, RegState::Kill)
389+
.addImm(Amount);
390+
New->getOperand(3).setIsDead();
391+
392+
BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP)
393+
.addReg(AVR::R31R30, RegState::Kill);
397394
}
398395

399396
return MBB.erase(MI);
@@ -420,7 +417,7 @@ struct AVRFrameAnalyzer : public MachineFunctionPass {
420417

421418
bool runOnMachineFunction(MachineFunction &MF) override {
422419
const MachineFrameInfo &MFI = MF.getFrameInfo();
423-
AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
420+
AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
424421

425422
// If there are no fixed frame indexes during this stage it means there
426423
// are allocas present in the function.
@@ -431,7 +428,7 @@ struct AVRFrameAnalyzer : public MachineFunctionPass {
431428
for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
432429
// Variable sized objects have size 0.
433430
if (MFI.getObjectSize(i)) {
434-
FuncInfo->setHasAllocas(true);
431+
AFI->setHasAllocas(true);
435432
break;
436433
}
437434
}
@@ -460,7 +457,7 @@ struct AVRFrameAnalyzer : public MachineFunctionPass {
460457
}
461458

462459
if (MFI.isFixedObjectIndex(MO.getIndex())) {
463-
FuncInfo->setHasStackArgs(true);
460+
AFI->setHasStackArgs(true);
464461
return false;
465462
}
466463
}

llvm/test/CodeGen/AVR/stdwstk.ll

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
; RUN: llc < %s -march=avr -mcpu=atmega328 -O1 | FileCheck %s
2+
; CHECK-NOT: stdwstk
3+
4+
; Checks that we expand STDWSPQRr always - even if it appears outside of the
5+
; FrameSetup/FrameDestroy context.
6+
7+
declare { } @foo(i128, i128) addrspace(1)
8+
9+
define i128 @bar(i128 %a, i128 %b) addrspace(1) {
10+
%b_neg = icmp slt i128 %b, 0
11+
%divisor = select i1 %b_neg, i128 0, i128 %b
12+
%result = tail call fastcc addrspace(1) { } @foo(i128 undef, i128 %divisor)
13+
14+
ret i128 0
15+
}

0 commit comments

Comments
 (0)