Skip to content

Commit 7faf1a0

Browse files
authored
[Sparc] Add errata workaround pass for GR712RC and UT700 (llvm#103843)
This patch adds a pass that provides workarounds for the errata described in GRLIB-TN-0009, GRLIB-TN-0010, GRLIB-TN-0011, GRLIB-TN-0012, and GRLIB-TN-0013, that are applicable to the GR712RC and UT700. The documents are available for download from here: https://www.gaisler.com/index.php/information/app-tech-notes The pass will detect certain sensitive instruction sequences and prevent them from occurring by inserting NOP instruction. Below is an overview of each of the workarounds. A similar implementation is available in GCC. GRLIB-TN-0009: * Insert NOPs to prevent the sequence (stb/sth/st/stf) -> (single non-store/load instruction) -> (any store) * Insert NOPs to prevent the sequence (std/stdf) -> (any store) GRLIB-TN-0010: * Insert a NOP between load instruction and atomic instruction (swap and casa). * Insert a NOP at branch target if load in delay slot and atomic instruction at branch target. * Do not allow functions to begin with atomic instruction. GRLIB-TN-0011: * Insert .p2align 4 before atomic instructions (swap and casa). GRLIB-TN-0012: * Place a NOP at the branch target of an integer branch if it is a floating-point operation or a floating-point branch. GRLIB-TN-0013: * Prevent (div/sqrt) instructions in the delay slot. * Insert NOPs to prevent the sequence (div/sqrt) -> (two or three floating point operations or loads) -> (div/sqrt). * Do not insert NOPs if any of the floating point operations have a dependency on the destination register of the first (div/sqrt). * Do not insert NOPs if one of the floating point operations is a (div/sqrt). * Insert NOPs to prevent (div/sqrt) followed by a branch.
1 parent 82fdfd4 commit 7faf1a0

File tree

12 files changed

+678
-0
lines changed

12 files changed

+678
-0
lines changed

llvm/lib/Target/Sparc/DelaySlotFiller.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,20 @@ bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate,
282282
Opcode >= SP::FDIVD && Opcode <= SP::FSQRTD)
283283
return true;
284284

285+
if (Subtarget->fixTN0009() && candidate->mayStore())
286+
return true;
287+
288+
if (Subtarget->fixTN0013()) {
289+
switch (Opcode) {
290+
case SP::FDIVS:
291+
case SP::FDIVD:
292+
case SP::FSQRTS:
293+
case SP::FSQRTD:
294+
return true;
295+
default:
296+
break;
297+
}
298+
}
285299

286300
return false;
287301
}

llvm/lib/Target/Sparc/LeonFeatures.td

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,38 @@ def FixAllFDIVSQRT : SubtargetFeature<
6161
def LeonCycleCounter
6262
: SubtargetFeature<"leoncyclecounter", "HasLeonCycleCounter", "true",
6363
"Use the Leon cycle counter register">;
64+
65+
def FixTN0009 : SubtargetFeature<
66+
"fix-tn0009",
67+
"FixTN0009",
68+
"true",
69+
"Enable workaround for errata described in GRLIB-TN-0009"
70+
>;
71+
72+
def FixTN0010 : SubtargetFeature<
73+
"fix-tn0010",
74+
"FixTN0010",
75+
"true",
76+
"Enable workaround for errata described in GRLIB-TN-0010"
77+
>;
78+
79+
def FixTN0011 : SubtargetFeature<
80+
"fix-tn0011",
81+
"FixTN0011",
82+
"true",
83+
"Enable workaround for errata described in GRLIB-TN-0011"
84+
>;
85+
86+
def FixTN0012 : SubtargetFeature<
87+
"fix-tn0012",
88+
"FixTN0012",
89+
"true",
90+
"Enable workaround for errata described in GRLIB-TN-0012"
91+
>;
92+
93+
def FixTN0013 : SubtargetFeature<
94+
"fix-tn0013",
95+
"FixTN0013",
96+
"true",
97+
"Enable workaround for errata described in GRLIB-TN-0013"
98+
>;

llvm/lib/Target/Sparc/LeonPasses.cpp

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,310 @@
1919

2020
using namespace llvm;
2121

22+
char ErrataWorkaround::ID = 0;
23+
24+
ErrataWorkaround::ErrataWorkaround() : MachineFunctionPass(ID) {
25+
initializeErrataWorkaroundPass(*PassRegistry::getPassRegistry());
26+
}
27+
28+
INITIALIZE_PASS(ErrataWorkaround, "errata-workaround", "Errata workaround pass",
29+
false, false)
30+
31+
// Move iterator to the next instruction in the function, ignoring
32+
// meta instructions and inline assembly. Returns false when reaching
33+
// the end of the function.
34+
bool ErrataWorkaround::moveNext(MachineBasicBlock::iterator &I) {
35+
36+
MachineBasicBlock *MBB = I->getParent();
37+
38+
do {
39+
I++;
40+
41+
while (I == MBB->end()) {
42+
if (MBB->getFallThrough() == nullptr)
43+
return false;
44+
MBB = MBB->getFallThrough();
45+
I = MBB->begin();
46+
}
47+
} while (I->isMetaInstruction() || I->isInlineAsm());
48+
49+
return true;
50+
}
51+
52+
void ErrataWorkaround::insertNop(MachineBasicBlock::iterator I) {
53+
BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(SP::NOP));
54+
}
55+
56+
bool ErrataWorkaround::isFloat(MachineBasicBlock::iterator I) {
57+
if (I->getNumOperands() == 0)
58+
return false;
59+
60+
if (!I->getOperand(0).isReg())
61+
return false;
62+
63+
unsigned reg = I->getOperand(0).getReg();
64+
65+
if (!SP::FPRegsRegClass.contains(reg) && !SP::DFPRegsRegClass.contains(reg))
66+
return false;
67+
68+
return true;
69+
}
70+
71+
bool ErrataWorkaround::isDivSqrt(MachineBasicBlock::iterator I) {
72+
switch (I->getOpcode()) {
73+
case SP::FDIVS:
74+
case SP::FDIVD:
75+
case SP::FSQRTS:
76+
case SP::FSQRTD:
77+
return true;
78+
}
79+
return false;
80+
}
81+
82+
// Prevents the following code sequence from being generated:
83+
// (stb/sth/st/stf) -> (single non-store/load instruction) -> (any store)
84+
// If the sequence is detected a NOP instruction is inserted after
85+
// the first store instruction.
86+
bool ErrataWorkaround::checkSeqTN0009A(MachineBasicBlock::iterator I) {
87+
switch (I->getOpcode()) {
88+
case SP::STrr:
89+
case SP::STri:
90+
case SP::STBrr:
91+
case SP::STBri:
92+
case SP::STHrr:
93+
case SP::STHri:
94+
case SP::STFrr:
95+
case SP::STFri:
96+
break;
97+
default:
98+
return false;
99+
}
100+
101+
MachineBasicBlock::iterator MI = I;
102+
if (!moveNext(MI))
103+
return false;
104+
105+
if (MI->mayStore() || MI->mayLoad())
106+
return false;
107+
108+
MachineBasicBlock::iterator PatchHere = MI;
109+
110+
if (!moveNext(MI))
111+
return false;
112+
113+
if (!MI->mayStore())
114+
return false;
115+
116+
insertNop(PatchHere);
117+
return true;
118+
}
119+
120+
// Prevents the following code sequence from being generated:
121+
// (std/stdf) -> (any store)
122+
// If the sequence is detected a NOP instruction is inserted after
123+
// the first store instruction.
124+
bool ErrataWorkaround::checkSeqTN0009B(MachineBasicBlock::iterator I) {
125+
126+
switch (I->getOpcode()) {
127+
case SP::STDrr:
128+
case SP::STDri:
129+
case SP::STDFrr:
130+
case SP::STDFri:
131+
break;
132+
default:
133+
return false;
134+
}
135+
136+
MachineBasicBlock::iterator MI = I;
137+
138+
if (!moveNext(MI))
139+
return false;
140+
141+
if (!MI->mayStore())
142+
return false;
143+
144+
insertNop(MI);
145+
return true;
146+
}
147+
148+
// Insert a NOP at branch target if load in delay slot and atomic
149+
// instruction at branch target. Also insert a NOP between load
150+
// instruction and atomic instruction (swap or casa).
151+
bool ErrataWorkaround::checkSeqTN0010(MachineBasicBlock::iterator I) {
152+
153+
// Check for load instruction or branch bundled with load instruction
154+
if (!I->mayLoad())
155+
return false;
156+
157+
// Check for branch to atomic instruction with load in delay slot
158+
if (I->isBranch()) {
159+
MachineBasicBlock *TargetMBB = I->getOperand(0).getMBB();
160+
MachineBasicBlock::iterator MI = TargetMBB->begin();
161+
162+
while (MI != TargetMBB->end() && MI->isMetaInstruction())
163+
MI++;
164+
165+
if (MI == TargetMBB->end())
166+
return false;
167+
168+
switch (MI->getOpcode()) {
169+
case SP::SWAPrr:
170+
case SP::SWAPri:
171+
case SP::CASArr:
172+
insertNop(MI);
173+
break;
174+
default:
175+
break;
176+
}
177+
}
178+
179+
// Check for load followed by atomic instruction
180+
MachineBasicBlock::iterator MI = I;
181+
if (!moveNext(MI))
182+
return false;
183+
184+
switch (MI->getOpcode()) {
185+
case SP::SWAPrr:
186+
case SP::SWAPri:
187+
case SP::CASArr:
188+
break;
189+
default:
190+
return false;
191+
}
192+
insertNop(MI);
193+
return true;
194+
}
195+
196+
// Do not allow functions to begin with an atomic instruction
197+
bool ErrataWorkaround::checkSeqTN0010First(MachineBasicBlock &MBB) {
198+
MachineBasicBlock::iterator I = MBB.begin();
199+
while (I != MBB.end() && I->isMetaInstruction())
200+
I++;
201+
switch (I->getOpcode()) {
202+
case SP::SWAPrr:
203+
case SP::SWAPri:
204+
case SP::CASArr:
205+
break;
206+
default:
207+
return false;
208+
}
209+
insertNop(I);
210+
return true;
211+
}
212+
213+
// Inserts a NOP instruction at the target of an integer branch if the
214+
// target is a floating-point instruction or floating-point branch.
215+
bool ErrataWorkaround::checkSeqTN0012(MachineBasicBlock::iterator I) {
216+
217+
if (I->getOpcode() != SP::BCOND && I->getOpcode() != SP::BCONDA)
218+
return false;
219+
220+
MachineBasicBlock *TargetMBB = I->getOperand(0).getMBB();
221+
MachineBasicBlock::iterator MI = TargetMBB->begin();
222+
223+
while (MI != TargetMBB->end() && MI->isMetaInstruction())
224+
MI++;
225+
226+
if (MI == TargetMBB->end())
227+
return false;
228+
229+
if (!isFloat(MI) && MI->getOpcode() != SP::FBCOND)
230+
return false;
231+
232+
insertNop(MI);
233+
return true;
234+
}
235+
236+
// Prevents the following code sequence from being generated:
237+
// (div/sqrt) -> (2 to 3 floating-point operations or loads) -> (div/sqrt)
238+
// If the sequence is detected one or two NOP instruction are inserted after
239+
// the first div/sqrt instruction. No NOPs are inserted if one of the floating-
240+
// point instructions in the middle of the sequence is a (div/sqrt), or if
241+
// they have dependency on the destination register of the first (div/sqrt).
242+
//
243+
// The function also prevents the following code sequence from being generated,
244+
// (div/sqrt) -> (branch), by inserting a NOP instruction after the (div/sqrt).
245+
bool ErrataWorkaround::checkSeqTN0013(MachineBasicBlock::iterator I) {
246+
247+
if (!isDivSqrt(I))
248+
return false;
249+
250+
unsigned dstReg = I->getOperand(0).getReg();
251+
252+
MachineBasicBlock::iterator MI = I;
253+
if (!moveNext(MI))
254+
return false;
255+
256+
if (MI->isBranch()) {
257+
insertNop(MI);
258+
return true;
259+
}
260+
261+
MachineBasicBlock::iterator PatchHere = MI;
262+
263+
unsigned fpFound = 0;
264+
for (unsigned i = 0; i < 4; i++) {
265+
266+
if (!isFloat(MI)) {
267+
if (!moveNext(MI))
268+
return false;
269+
continue;
270+
}
271+
272+
if (MI->readsRegister(dstReg, TRI))
273+
return false;
274+
275+
if (isDivSqrt(MI)) {
276+
if (i < 2)
277+
return false;
278+
if (fpFound < 2)
279+
return false;
280+
281+
insertNop(PatchHere);
282+
if (i == 2)
283+
insertNop(PatchHere);
284+
return true;
285+
}
286+
287+
fpFound++;
288+
if (!moveNext(MI))
289+
return false;
290+
}
291+
292+
return false;
293+
}
294+
295+
bool ErrataWorkaround::runOnMachineFunction(MachineFunction &MF) {
296+
bool Changed = false;
297+
ST = &MF.getSubtarget<SparcSubtarget>();
298+
299+
if (!(ST->fixTN0009() || ST->fixTN0010() || ST->fixTN0012() ||
300+
ST->fixTN0013()))
301+
return false;
302+
303+
TII = ST->getInstrInfo();
304+
TRI = ST->getRegisterInfo();
305+
306+
if (ST->fixTN0010())
307+
Changed |= checkSeqTN0010First(MF.front());
308+
309+
for (auto &MBB : MF) {
310+
for (auto &I : MBB) {
311+
if (ST->fixTN0009()) {
312+
Changed |= checkSeqTN0009A(I);
313+
Changed |= checkSeqTN0009B(I);
314+
}
315+
if (ST->fixTN0010())
316+
Changed |= checkSeqTN0010(I);
317+
if (ST->fixTN0012())
318+
Changed |= checkSeqTN0012(I);
319+
if (ST->fixTN0013())
320+
Changed |= checkSeqTN0013(I);
321+
}
322+
}
323+
return Changed;
324+
}
325+
22326
LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID)
23327
: MachineFunctionPass(ID) {}
24328

0 commit comments

Comments
 (0)