llvm.org GIT mirror llvm / 261c94d
[lanai] Use peephole optimizer to generate more conditional ALU operations. Summary: * Similiar to the ARM backend yse the peephole optimizer to generate more conditional ALU operations; * Add predicated type with default always true to RR instructions in LanaiInstrInfo.td; * Move LanaiSetflagAluCombiner into optimizeCompare; * The ASM parser can currently only handle explicitly specified CC, so specify ".t" (true) where needed in the ASM test; * Remove unused MachineOperand flags; Reviewers: eliben Subscribers: aemerson Differential Revision: http://reviews.llvm.org/D22072 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@274807 91177308-0d34-0410-b5e6-96231b3b80d8 Jacques Pienaar 3 years ago
20 changed file(s) with 1562 addition(s) and 552 deletion(s). Raw diff Collapse all Expand all
356356 return isInt<10>(Value);
357357 }
358358
359 bool isCondCode() {
360 if (!isImm())
361 return false;
362
363 const MCConstantExpr *ConstExpr = dyn_cast(Imm.Value);
364 if (!ConstExpr)
365 return false;
366 uint64_t Value = ConstExpr->getValue();
367 // The condition codes are between 0 (ICC_T) and 15 (ICC_LE). If the
368 // unsigned value of the immediate is less than LPCC::UNKNOWN (16) then
369 // value corresponds to a valid condition code.
370 return Value < LPCC::UNKNOWN;
371 }
372
359373 void addExpr(MCInst &Inst, const MCExpr *Expr) const {
360374 // Add as immediates where possible. Null MCExpr = 0
361375 if (Expr == nullptr)
383397 }
384398
385399 void addCallTargetOperands(MCInst &Inst, unsigned N) const {
400 assert(N == 1 && "Invalid number of operands!");
401 addExpr(Inst, getImm());
402 }
403
404 void addCondCodeOperands(MCInst &Inst, unsigned N) const {
386405 assert(N == 1 && "Invalid number of operands!");
387406 addExpr(Inst, getImm());
388407 }
10301049 LPCC::CondCode CondCode = LPCC::suffixToLanaiCondCode(Mnemonic);
10311050 if (CondCode != LPCC::UNKNOWN) {
10321051 size_t Next = Mnemonic.rfind('.', Name.size());
1033 Mnemonic = Mnemonic.substr(0, Next + 1);
1052 // 'sel' doesn't use a predicate operand whose printer adds the period,
1053 // but instead has the period as part of the identifier (i.e., 'sel.' is
1054 // expected by the generated matcher). If the mnemonic starts with 'sel'
1055 // then include the period as part of the mnemonic, else don't include it
1056 // as part of the mnemonic.
1057 if (Mnemonic.startswith("sel")) {
1058 Mnemonic = Mnemonic.substr(0, Next + 1);
1059 } else {
1060 Mnemonic = Mnemonic.substr(0, Next);
1061 }
10341062 Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));
10351063 Operands->push_back(LanaiOperand::createImm(
10361064 MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc));
2222 LanaiMemAluCombiner.cpp
2323 LanaiRegisterInfo.cpp
2424 LanaiSelectionDAGInfo.cpp
25 LanaiSetflagAluCombiner.cpp
2625 LanaiSubtarget.cpp
2726 LanaiTargetMachine.cpp
2827 LanaiTargetObjectFile.cpp
6060
6161 static DecodeStatus decodeBranch(MCInst &Inst, unsigned Insn, uint64_t Address,
6262 const void *Decoder);
63
64 static DecodeStatus decodePredicateOperand(MCInst &Inst, unsigned Val,
65 uint64_t Address,
66 const void *Decoder);
6367
6468 static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn,
6569 uint64_t Address, const void *Decoder);
225229
226230 return MCDisassembler::Success;
227231 }
232
233 static DecodeStatus decodePredicateOperand(MCInst &Inst, unsigned Val,
234 uint64_t Address,
235 const void *Decoder) {
236 if (Val >= LPCC::UNKNOWN)
237 return MCDisassembler::Fail;
238 Inst.addOperand(MCOperand::createImm(Val));
239 return MCDisassembler::Success;
240 }
283283
284284 void LanaiInstPrinter::printCCOperand(const MCInst *MI, int OpNo,
285285 raw_ostream &OS) {
286 const int CC = static_cast(MI->getOperand(OpNo).getImm());
287 OS << lanaiCondCodeToString(static_cast(CC));
288 }
286 LPCC::CondCode CC =
287 static_cast(MI->getOperand(OpNo).getImm());
288 // Handle the undefined value here for printing so we don't abort().
289 if (CC >= LPCC::UNKNOWN)
290 OS << "";
291 else
292 OS << lanaiCondCodeToString(CC);
293 }
294
295 void LanaiInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo,
296 raw_ostream &OS) {
297 LPCC::CondCode CC =
298 static_cast(MI->getOperand(OpNo).getImm());
299 // Handle the undefined value here for printing so we don't abort().
300 if (CC >= LPCC::UNKNOWN)
301 OS << "";
302 else if (CC != LPCC::ICC_T)
303 OS << "." << lanaiCondCodeToString(CC);
304 }
2828 const MCSubtargetInfo &STI) override;
2929 void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O,
3030 const char *Modifier = 0);
31 void printPredicateOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
3132 void printMemRiOperand(const MCInst *MI, int OpNo, raw_ostream &O,
3233 const char *Modifier = 0);
3334 void printMemRrOperand(const MCInst *MI, int OpNo, raw_ostream &O,
6464 void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
6565 raw_ostream &O, const char *Modifier) {
6666 const MachineOperand &MO = MI->getOperand(OpNum);
67 unsigned TF = MO.getTargetFlags();
6867
6968 switch (MO.getType()) {
7069 case MachineOperand::MO_Register:
8079 break;
8180
8281 case MachineOperand::MO_GlobalAddress:
83 if (TF == LanaiII::MO_PLT)
84 O << "plt(" << *getSymbol(MO.getGlobal()) << ")";
85 else
86 O << *getSymbol(MO.getGlobal());
82 O << *getSymbol(MO.getGlobal());
8783 break;
8884
8985 case MachineOperand::MO_BlockAddress: {
9389 }
9490
9591 case MachineOperand::MO_ExternalSymbol:
96 if (TF == LanaiII::MO_PLT)
97 O << "plt(" << *GetExternalSymbolSymbol(MO.getSymbolName()) << ")";
98 else
99 O << *GetExternalSymbolSymbol(MO.getSymbolName());
92 O << *GetExternalSymbolSymbol(MO.getSymbolName());
10093 break;
10194
10295 case MachineOperand::MO_JumpTableIndex:
115108 }
116109
117110 // PrintAsmOperand - Print out an operand for an inline asm expression.
118 //
119111 bool LanaiAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
120112 unsigned AsmVariant,
121113 const char *ExtraCode, raw_ostream &O) {
122122 setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote);
123123 setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);
124124 }
125
126 setTargetDAGCombine(ISD::ADD);
127 setTargetDAGCombine(ISD::SUB);
128 setTargetDAGCombine(ISD::AND);
129 setTargetDAGCombine(ISD::OR);
130 setTargetDAGCombine(ISD::XOR);
125131
126132 // Function alignments (log2)
127133 setMinFunctionAlignment(2);
12671273 SDValue Ops[2] = {Lo, Hi};
12681274 return DAG.getMergeValues(Ops, dl);
12691275 }
1276
1277 // Helper function that checks if N is a null or all ones constant.
1278 static inline bool isZeroOrAllOnes(SDValue N, bool AllOnes) {
1279 return AllOnes ? isAllOnesConstant(N) : isNullConstant(N);
1280 }
1281
1282 // Return true if N is conditionally 0 or all ones.
1283 // Detects these expressions where cc is an i1 value:
1284 //
1285 // (select cc 0, y) [AllOnes=0]
1286 // (select cc y, 0) [AllOnes=0]
1287 // (zext cc) [AllOnes=0]
1288 // (sext cc) [AllOnes=0/1]
1289 // (select cc -1, y) [AllOnes=1]
1290 // (select cc y, -1) [AllOnes=1]
1291 //
1292 // * AllOnes determines whether to check for an all zero (AllOnes false) or an
1293 // all ones operand (AllOnes true).
1294 // * Invert is set when N is the all zero/ones constant when CC is false.
1295 // * OtherOp is set to the alternative value of N.
1296 //
1297 // For example, for (select cc X, Y) and AllOnes = 0 if:
1298 // * X = 0, Invert = False and OtherOp = Y
1299 // * Y = 0, Invert = True and OtherOp = X
1300 static bool isConditionalZeroOrAllOnes(SDNode *N, bool AllOnes, SDValue &CC,
1301 bool &Invert, SDValue &OtherOp,
1302 SelectionDAG &DAG) {
1303 switch (N->getOpcode()) {
1304 default:
1305 return false;
1306 case ISD::SELECT: {
1307 CC = N->getOperand(0);
1308 SDValue N1 = N->getOperand(1);
1309 SDValue N2 = N->getOperand(2);
1310 if (isZeroOrAllOnes(N1, AllOnes)) {
1311 Invert = false;
1312 OtherOp = N2;
1313 return true;
1314 }
1315 if (isZeroOrAllOnes(N2, AllOnes)) {
1316 Invert = true;
1317 OtherOp = N1;
1318 return true;
1319 }
1320 return false;
1321 }
1322 case ISD::ZERO_EXTEND: {
1323 // (zext cc) can never be the all ones value.
1324 if (AllOnes)
1325 return false;
1326 CC = N->getOperand(0);
1327 if (CC.getValueType() != MVT::i1)
1328 return false;
1329 SDLoc dl(N);
1330 EVT VT = N->getValueType(0);
1331 OtherOp = DAG.getConstant(1, dl, VT);
1332 Invert = true;
1333 return true;
1334 }
1335 case ISD::SIGN_EXTEND: {
1336 CC = N->getOperand(0);
1337 if (CC.getValueType() != MVT::i1)
1338 return false;
1339 SDLoc dl(N);
1340 EVT VT = N->getValueType(0);
1341 Invert = !AllOnes;
1342 if (AllOnes)
1343 // When looking for an AllOnes constant, N is an sext, and the 'other'
1344 // value is 0.
1345 OtherOp = DAG.getConstant(0, dl, VT);
1346 else
1347 OtherOp =
1348 DAG.getConstant(APInt::getAllOnesValue(VT.getSizeInBits()), dl, VT);
1349 return true;
1350 }
1351 }
1352 }
1353
1354 // Combine a constant select operand into its use:
1355 //
1356 // (add (select cc, 0, c), x) -> (select cc, x, (add, x, c))
1357 // (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c))
1358 // (and (select cc, -1, c), x) -> (select cc, x, (and, x, c)) [AllOnes=1]
1359 // (or (select cc, 0, c), x) -> (select cc, x, (or, x, c))
1360 // (xor (select cc, 0, c), x) -> (select cc, x, (xor, x, c))
1361 //
1362 // The transform is rejected if the select doesn't have a constant operand that
1363 // is null, or all ones when AllOnes is set.
1364 //
1365 // Also recognize sext/zext from i1:
1366 //
1367 // (add (zext cc), x) -> (select cc (add x, 1), x)
1368 // (add (sext cc), x) -> (select cc (add x, -1), x)
1369 //
1370 // These transformations eventually create predicated instructions.
1371 static SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp,
1372 TargetLowering::DAGCombinerInfo &DCI,
1373 bool AllOnes) {
1374 SelectionDAG &DAG = DCI.DAG;
1375 EVT VT = N->getValueType(0);
1376 SDValue NonConstantVal;
1377 SDValue CCOp;
1378 bool SwapSelectOps;
1379 if (!isConditionalZeroOrAllOnes(Slct.getNode(), AllOnes, CCOp, SwapSelectOps,
1380 NonConstantVal, DAG))
1381 return SDValue();
1382
1383 // Slct is now know to be the desired identity constant when CC is true.
1384 SDValue TrueVal = OtherOp;
1385 SDValue FalseVal =
1386 DAG.getNode(N->getOpcode(), SDLoc(N), VT, OtherOp, NonConstantVal);
1387 // Unless SwapSelectOps says CC should be false.
1388 if (SwapSelectOps)
1389 std::swap(TrueVal, FalseVal);
1390
1391 return DAG.getNode(ISD::SELECT, SDLoc(N), VT, CCOp, TrueVal, FalseVal);
1392 }
1393
1394 // Attempt combineSelectAndUse on each operand of a commutative operator N.
1395 static SDValue
1396 combineSelectAndUseCommutative(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
1397 bool AllOnes) {
1398 SDValue N0 = N->getOperand(0);
1399 SDValue N1 = N->getOperand(1);
1400 if (N0.getNode()->hasOneUse())
1401 if (SDValue Result = combineSelectAndUse(N, N0, N1, DCI, AllOnes))
1402 return Result;
1403 if (N1.getNode()->hasOneUse())
1404 if (SDValue Result = combineSelectAndUse(N, N1, N0, DCI, AllOnes))
1405 return Result;
1406 return SDValue();
1407 }
1408
1409 // PerformSUBCombine - Target-specific dag combine xforms for ISD::SUB.
1410 static SDValue PerformSUBCombine(SDNode *N,
1411 TargetLowering::DAGCombinerInfo &DCI) {
1412 SDValue N0 = N->getOperand(0);
1413 SDValue N1 = N->getOperand(1);
1414
1415 // fold (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c))
1416 if (N1.getNode()->hasOneUse())
1417 if (SDValue Result = combineSelectAndUse(N, N1, N0, DCI, /*AllOnes=*/false))
1418 return Result;
1419
1420 return SDValue();
1421 }
1422
1423 SDValue LanaiTargetLowering::PerformDAGCombine(SDNode *N,
1424 DAGCombinerInfo &DCI) const {
1425 switch (N->getOpcode()) {
1426 default:
1427 break;
1428 case ISD::ADD:
1429 case ISD::OR:
1430 case ISD::XOR:
1431 return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/false);
1432 case ISD::AND:
1433 return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/true);
1434 case ISD::SUB:
1435 return PerformSUBCombine(N, DCI);
1436 }
1437
1438 return SDValue();
1439 }
102102 std::vector &Ops,
103103 SelectionDAG &DAG) const override;
104104
105 SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override;
106
105107 private:
106108 SDValue LowerCCCCallTo(SDValue Chain, SDValue Callee,
107109 CallingConv::ID CallConv, bool IsVarArg,
121121 return false;
122122 }
123123
124 static LPCC::CondCode GetOppositeBranchCondition(LPCC::CondCode CC) {
124 static LPCC::CondCode getOppositeCondition(LPCC::CondCode CC) {
125125 switch (CC) {
126126 case LPCC::ICC_T: // true
127127 return LPCC::ICC_F;
160160 }
161161 }
162162
163 std::pair
164 LanaiInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
165 return std::make_pair(TF, 0u);
166 }
167
168 ArrayRef>
169 LanaiInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
170 using namespace LanaiII;
171 static const std::pair TargetFlags[] = {
172 {MO_ABS_HI, "lanai-hi"},
173 {MO_ABS_LO, "lanai-lo"},
174 {MO_NO_FLAG, "lanai-nf"}};
175 return makeArrayRef(TargetFlags);
176 }
177
178 bool LanaiInstrInfo::analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
179 unsigned &SrcReg2, int &CmpMask,
180 int &CmpValue) const {
181 switch (MI.getOpcode()) {
182 default:
183 break;
184 case Lanai::SFSUB_F_RI_LO:
185 case Lanai::SFSUB_F_RI_HI:
186 SrcReg = MI.getOperand(0).getReg();
187 SrcReg2 = 0;
188 CmpMask = ~0;
189 CmpValue = MI.getOperand(1).getImm();
190 return true;
191 case Lanai::SFSUB_F_RR:
192 SrcReg = MI.getOperand(0).getReg();
193 SrcReg2 = MI.getOperand(1).getReg();
194 CmpMask = ~0;
195 CmpValue = 0;
196 return true;
197 }
198
199 return false;
200 }
201
202 // isRedundantFlagInstr - check whether the first instruction, whose only
203 // purpose is to update flags, can be made redundant.
204 // * SFSUB_F_RR can be made redundant by SUB_RI if the operands are the same.
205 // * SFSUB_F_RI can be made redundant by SUB_I if the operands are the same.
206 inline static bool isRedundantFlagInstr(MachineInstr *CmpI, unsigned SrcReg,
207 unsigned SrcReg2, int ImmValue,
208 MachineInstr *OI) {
209 if (CmpI->getOpcode() == Lanai::SFSUB_F_RR &&
210 OI->getOpcode() == Lanai::SUB_R &&
211 ((OI->getOperand(1).getReg() == SrcReg &&
212 OI->getOperand(2).getReg() == SrcReg2) ||
213 (OI->getOperand(1).getReg() == SrcReg2 &&
214 OI->getOperand(2).getReg() == SrcReg)))
215 return true;
216
217 if (((CmpI->getOpcode() == Lanai::SFSUB_F_RI_LO &&
218 OI->getOpcode() == Lanai::SUB_I_LO) ||
219 (CmpI->getOpcode() == Lanai::SFSUB_F_RI_HI &&
220 OI->getOpcode() == Lanai::SUB_I_HI)) &&
221 OI->getOperand(1).getReg() == SrcReg &&
222 OI->getOperand(2).getImm() == ImmValue)
223 return true;
224 return false;
225 }
226
227 inline static unsigned flagSettingOpcodeVariant(unsigned OldOpcode) {
228 switch (OldOpcode) {
229 case Lanai::ADD_I_HI:
230 return Lanai::ADD_F_I_HI;
231 case Lanai::ADD_I_LO:
232 return Lanai::ADD_F_I_LO;
233 case Lanai::ADD_R:
234 return Lanai::ADD_F_R;
235 case Lanai::ADDC_I_HI:
236 return Lanai::ADDC_F_I_HI;
237 case Lanai::ADDC_I_LO:
238 return Lanai::ADDC_F_I_LO;
239 case Lanai::ADDC_R:
240 return Lanai::ADDC_F_R;
241 case Lanai::AND_I_HI:
242 return Lanai::AND_F_I_HI;
243 case Lanai::AND_I_LO:
244 return Lanai::AND_F_I_LO;
245 case Lanai::AND_R:
246 return Lanai::AND_F_R;
247 case Lanai::OR_I_HI:
248 return Lanai::OR_F_I_HI;
249 case Lanai::OR_I_LO:
250 return Lanai::OR_F_I_LO;
251 case Lanai::OR_R:
252 return Lanai::OR_F_R;
253 case Lanai::SL_I:
254 return Lanai::SL_F_I;
255 case Lanai::SRL_R:
256 return Lanai::SRL_F_R;
257 case Lanai::SA_I:
258 return Lanai::SA_F_I;
259 case Lanai::SRA_R:
260 return Lanai::SRA_F_R;
261 case Lanai::SUB_I_HI:
262 return Lanai::SUB_F_I_HI;
263 case Lanai::SUB_I_LO:
264 return Lanai::SUB_F_I_LO;
265 case Lanai::SUB_R:
266 return Lanai::SUB_F_R;
267 case Lanai::SUBB_I_HI:
268 return Lanai::SUBB_F_I_HI;
269 case Lanai::SUBB_I_LO:
270 return Lanai::SUBB_F_I_LO;
271 case Lanai::SUBB_R:
272 return Lanai::SUBB_F_R;
273 case Lanai::XOR_I_HI:
274 return Lanai::XOR_F_I_HI;
275 case Lanai::XOR_I_LO:
276 return Lanai::XOR_F_I_LO;
277 case Lanai::XOR_R:
278 return Lanai::XOR_F_R;
279 default:
280 return Lanai::NOP;
281 }
282 }
283
284 bool LanaiInstrInfo::optimizeCompareInstr(
285 MachineInstr &CmpInstr, unsigned SrcReg, unsigned SrcReg2, int CmpMask,
286 int CmpValue, const MachineRegisterInfo *MRI) const {
287 // Get the unique definition of SrcReg.
288 MachineInstr *MI = MRI->getUniqueVRegDef(SrcReg);
289 if (!MI)
290 return false;
291
292 // Get ready to iterate backward from CmpInstr.
293 MachineBasicBlock::iterator I = CmpInstr, E = MI,
294 B = CmpInstr.getParent()->begin();
295
296 // Early exit if CmpInstr is at the beginning of the BB.
297 if (I == B)
298 return false;
299
300 // There are two possible candidates which can be changed to set SR:
301 // One is MI, the other is a SUB instruction.
302 // * For SFSUB_F_RR(r1,r2), we are looking for SUB(r1,r2) or SUB(r2,r1).
303 // * For SFSUB_F_RI(r1, CmpValue), we are looking for SUB(r1, CmpValue).
304 MachineInstr *Sub = nullptr;
305 if (SrcReg2 != 0)
306 // MI is not a candidate to transform into a flag setting instruction.
307 MI = nullptr;
308 else if (MI->getParent() != CmpInstr.getParent() || CmpValue != 0) {
309 // Conservatively refuse to convert an instruction which isn't in the same
310 // BB as the comparison. Don't return if SFSUB_F_RI and CmpValue != 0 as Sub
311 // may still be a candidate.
312 if (CmpInstr.getOpcode() == Lanai::SFSUB_F_RI_LO)
313 MI = nullptr;
314 else
315 return false;
316 }
317
318 // Check that SR isn't set between the comparison instruction and the
319 // instruction we want to change while searching for Sub.
320 const TargetRegisterInfo *TRI = &getRegisterInfo();
321 for (--I; I != E; --I) {
322 const MachineInstr &Instr = *I;
323
324 if (Instr.modifiesRegister(Lanai::SR, TRI) ||
325 Instr.readsRegister(Lanai::SR, TRI))
326 // This instruction modifies or uses SR after the one we want to change.
327 // We can't do this transformation.
328 return false;
329
330 // Check whether CmpInstr can be made redundant by the current instruction.
331 if (isRedundantFlagInstr(&CmpInstr, SrcReg, SrcReg2, CmpValue, &*I)) {
332 Sub = &*I;
333 break;
334 }
335
336 // Don't search outside the containing basic block.
337 if (I == B)
338 return false;
339 }
340
341 // Return false if no candidates exist.
342 if (!MI && !Sub)
343 return false;
344
345 // The single candidate is called MI.
346 if (!MI)
347 MI = Sub;
348
349 if (flagSettingOpcodeVariant(MI->getOpcode()) != Lanai::NOP) {
350 bool isSafe = false;
351
352 SmallVector, 4>
353 OperandsToUpdate;
354 I = CmpInstr;
355 E = CmpInstr.getParent()->end();
356 while (!isSafe && ++I != E) {
357 const MachineInstr &Instr = *I;
358 for (unsigned IO = 0, EO = Instr.getNumOperands(); !isSafe && IO != EO;
359 ++IO) {
360 const MachineOperand &MO = Instr.getOperand(IO);
361 if (MO.isRegMask() && MO.clobbersPhysReg(Lanai::SR)) {
362 isSafe = true;
363 break;
364 }
365 if (!MO.isReg() || MO.getReg() != Lanai::SR)
366 continue;
367 if (MO.isDef()) {
368 isSafe = true;
369 break;
370 }
371 // Condition code is after the operand before SR.
372 LPCC::CondCode CC;
373 CC = (LPCC::CondCode)Instr.getOperand(IO - 1).getImm();
374
375 if (Sub) {
376 LPCC::CondCode NewCC = getOppositeCondition(CC);
377 if (NewCC == LPCC::ICC_T)
378 return false;
379 // If we have SUB(r1, r2) and CMP(r2, r1), the condition code based on
380 // CMP needs to be updated to be based on SUB. Push the condition
381 // code operands to OperandsToUpdate. If it is safe to remove
382 // CmpInstr, the condition code of these operands will be modified.
383 if (SrcReg2 != 0 && Sub->getOperand(1).getReg() == SrcReg2 &&
384 Sub->getOperand(2).getReg() == SrcReg) {
385 OperandsToUpdate.push_back(
386 std::make_pair(&((*I).getOperand(IO - 1)), NewCC));
387 }
388 } else {
389 // No Sub, so this is x = y, z; cmp x, 0.
390 switch (CC) {
391 case LPCC::ICC_EQ: // Z
392 case LPCC::ICC_NE: // Z
393 case LPCC::ICC_MI: // N
394 case LPCC::ICC_PL: // N
395 case LPCC::ICC_F: // none
396 case LPCC::ICC_T: // none
397 // SR can be used multiple times, we should continue.
398 break;
399 case LPCC::ICC_CS: // C
400 case LPCC::ICC_CC: // C
401 case LPCC::ICC_VS: // V
402 case LPCC::ICC_VC: // V
403 case LPCC::ICC_HI: // C Z
404 case LPCC::ICC_LS: // C Z
405 case LPCC::ICC_GE: // N V
406 case LPCC::ICC_LT: // N V
407 case LPCC::ICC_GT: // Z N V
408 case LPCC::ICC_LE: // Z N V
409 // The instruction uses the V bit or C bit which is not safe.
410 return false;
411 case LPCC::UNKNOWN:
412 return false;
413 }
414 }
415 }
416 }
417
418 // If SR is not killed nor re-defined, we should check whether it is
419 // live-out. If it is live-out, do not optimize.
420 if (!isSafe) {
421 MachineBasicBlock *MBB = CmpInstr.getParent();
422 for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(),
423 SE = MBB->succ_end();
424 SI != SE; ++SI)
425 if ((*SI)->isLiveIn(Lanai::SR))
426 return false;
427 }
428
429 // Toggle the optional operand to SR.
430 MI->setDesc(get(flagSettingOpcodeVariant(MI->getOpcode())));
431 MI->addRegisterDefined(Lanai::SR);
432 CmpInstr.eraseFromParent();
433 return true;
434 }
435
436 return false;
437 }
438
439 bool LanaiInstrInfo::analyzeSelect(const MachineInstr &MI,
440 SmallVectorImpl &Cond,
441 unsigned &TrueOp, unsigned &FalseOp,
442 bool &Optimizable) const {
443 assert(MI.getOpcode() == Lanai::SELECT && "unknown select instruction");
444 // Select operands:
445 // 0: Def.
446 // 1: True use.
447 // 2: False use.
448 // 3: Condition code.
449 TrueOp = 1;
450 FalseOp = 2;
451 Cond.push_back(MI.getOperand(3));
452 Optimizable = true;
453 return false;
454 }
455
456 // Identify instructions that can be folded into a SELECT instruction, and
457 // return the defining instruction.
458 static MachineInstr *canFoldIntoSelect(unsigned Reg,
459 const MachineRegisterInfo &MRI,
460 const TargetInstrInfo *TII) {
461 if (!TargetRegisterInfo::isVirtualRegister(Reg))
462 return nullptr;
463 if (!MRI.hasOneNonDBGUse(Reg))
464 return nullptr;
465 MachineInstr *MI = MRI.getVRegDef(Reg);
466 if (!MI)
467 return nullptr;
468 // MI is folded into the SELECT by predicating it.
469 if (!MI->isPredicable())
470 return nullptr;
471 // Check if MI has any non-dead defs or physreg uses. This also detects
472 // predicated instructions which will be reading SR.
473 for (unsigned i = 1, e = MI->getNumOperands(); i != e; ++i) {
474 const MachineOperand &MO = MI->getOperand(i);
475 // Reject frame index operands.
476 if (MO.isFI() || MO.isCPI() || MO.isJTI())
477 return nullptr;
478 if (!MO.isReg())
479 continue;
480 // MI can't have any tied operands, that would conflict with predication.
481 if (MO.isTied())
482 return nullptr;
483 if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
484 return nullptr;
485 if (MO.isDef() && !MO.isDead())
486 return nullptr;
487 }
488 bool DontMoveAcrossStores = true;
489 if (!MI->isSafeToMove(/*AliasAnalysis=*/nullptr, DontMoveAcrossStores))
490 return nullptr;
491 return MI;
492 }
493
494 MachineInstr *
495 LanaiInstrInfo::optimizeSelect(MachineInstr &MI,
496 SmallPtrSetImpl &SeenMIs,
497 bool PreferFalse) const {
498 assert(MI.getOpcode() == Lanai::SELECT && "unknown select instruction");
499 MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
500 MachineInstr *DefMI = canFoldIntoSelect(MI.getOperand(1).getReg(), MRI, this);
501 bool Invert = !DefMI;
502 if (!DefMI)
503 DefMI = canFoldIntoSelect(MI.getOperand(2).getReg(), MRI, this);
504 if (!DefMI)
505 return nullptr;
506
507 // Find new register class to use.
508 MachineOperand FalseReg = MI.getOperand(Invert ? 1 : 2);
509 unsigned DestReg = MI.getOperand(0).getReg();
510 const TargetRegisterClass *PreviousClass = MRI.getRegClass(FalseReg.getReg());
511 if (!MRI.constrainRegClass(DestReg, PreviousClass))
512 return nullptr;
513
514 // Create a new predicated version of DefMI.
515 MachineInstrBuilder NewMI =
516 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), DefMI->getDesc(), DestReg);
517
518 // Copy all the DefMI operands, excluding its (null) predicate.
519 const MCInstrDesc &DefDesc = DefMI->getDesc();
520 for (unsigned i = 1, e = DefDesc.getNumOperands();
521 i != e && !DefDesc.OpInfo[i].isPredicate(); ++i)
522 NewMI.addOperand(DefMI->getOperand(i));
523
524 unsigned CondCode = MI.getOperand(3).getImm();
525 if (Invert)
526 NewMI.addImm(getOppositeCondition(LPCC::CondCode(CondCode)));
527 else
528 NewMI.addImm(CondCode);
529 NewMI.copyImplicitOps(MI);
530
531 // The output register value when the predicate is false is an implicit
532 // register operand tied to the first def. The tie makes the register
533 // allocator ensure the FalseReg is allocated the same register as operand 0.
534 FalseReg.setImplicit();
535 NewMI.addOperand(FalseReg);
536 NewMI->tieOperands(0, NewMI->getNumOperands() - 1);
537
538 // Update SeenMIs set: register newly created MI and erase removed DefMI.
539 SeenMIs.insert(NewMI);
540 SeenMIs.erase(DefMI);
541
542 // If MI is inside a loop, and DefMI is outside the loop, then kill flags on
543 // DefMI would be invalid when transferred inside the loop. Checking for a
544 // loop is expensive, but at least remove kill flags if they are in different
545 // BBs.
546 if (DefMI->getParent() != MI.getParent())
547 NewMI->clearKillInfo();
548
549 // The caller will erase MI, but not DefMI.
550 DefMI->eraseFromParent();
551 return NewMI;
552 }
553
163554 // The AnalyzeBranch function is used to examine conditional instructions and
164555 // remove unnecessary instructions. This method is used by BranchFolder and
165556 // IfConverter machine function passes to improve the CFG.
261652
262653 LPCC::CondCode BranchCond =
263654 static_cast(Condition[0].getImm());
264 Condition[0].setImm(GetOppositeBranchCondition(BranchCond));
655 Condition[0].setImm(getOppositeCondition(BranchCond));
265656 return false;
266657 }
267658
7474 int64_t &Offset, unsigned &Width,
7575 const TargetRegisterInfo *TRI) const;
7676
77 std::pair
78 decomposeMachineOperandsTargetFlags(unsigned TF) const override;
79
80 ArrayRef>
81 getSerializableDirectMachineOperandTargetFlags() const override;
82
7783 bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TrueBlock,
7884 MachineBasicBlock *&FalseBlock,
7985 SmallVectorImpl &Condition,
8086 bool AllowModify) const override;
8187
8288 unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
89
90 // For a comparison instruction, return the source registers in SrcReg and
91 // SrcReg2 if having two register operands, and the value it compares against
92 // in CmpValue. Return true if the comparison instruction can be analyzed.
93 bool analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
94 unsigned &SrcReg2, int &CmpMask,
95 int &CmpValue) const override;
96
97 // See if the comparison instruction can be converted into something more
98 // efficient. E.g., on Lanai register-register instructions can set the flag
99 // register, obviating the need for a separate compare.
100 bool optimizeCompareInstr(MachineInstr &CmpInstr, unsigned SrcReg,
101 unsigned SrcReg2, int CmpMask, int CmpValue,
102 const MachineRegisterInfo *MRI) const override;
103
104 // Analyze the given select instruction, returning true if it cannot be
105 // understood. It is assumed that MI->isSelect() is true.
106 //
107 // When successful, return the controlling condition and the operands that
108 // determine the true and false result values.
109 //
110 // Result = SELECT Cond, TrueOp, FalseOp
111 //
112 // Lanai can optimize certain select instructions, for example by predicating
113 // the instruction defining one of the operands and sets Optimizable to true.
114 bool analyzeSelect(const MachineInstr &MI,
115 SmallVectorImpl &Cond, unsigned &TrueOp,
116 unsigned &FalseOp, bool &Optimizable) const override;
117
118 // Given a select instruction that was understood by analyzeSelect and
119 // returned Optimizable = true, attempt to optimize MI by merging it with one
120 // of its operands. Returns NULL on failure.
121 //
122 // When successful, returns the new select instruction. The client is
123 // responsible for deleting MI.
124 //
125 // If both sides of the select can be optimized, the TrueOp is modifed.
126 // PreferFalse is not used.
127 MachineInstr *optimizeSelect(MachineInstr &MI,
128 SmallPtrSetImpl &SeenMIs,
129 bool PreferFalse) const override;
83130
84131 bool ReverseBranchCondition(
85132 SmallVectorImpl &Condition) const override;
234234 let PrintMethod = "printCCOperand";
235235 }
236236
237 // Predicate operand. Default to 0 = true.
238 def CondCodeOperand : AsmOperandClass { let Name = "CondCode"; }
239
240 def pred : PredicateOperand {
241 let PrintMethod = "printPredicateOperand";
242 let ParserMatchClass = CondCodeOperand;
243 let DecoderMethod = "decodePredicateOperand";
244 }
245
237246 let hasSideEffects = 0, Inst = 0x00000001 in
238247 def NOP : InstLanai<(outs), (ins), "nop", []>;
239248
282291 defm I_ : ALUbase;
283292
284293 // Register Register
285 let JJJJJ = 0, DDDI = 0 in
286 def R : InstRR
287 !strconcat(AsmStr, "\t$Rs1, $Rs2, $Rd"),
294 let JJJJJ = 0 in
295 def R : InstRR
296 !strconcat(AsmStr, "$DDDI\t$Rs1, $Rs2, $Rd"),
288297 [(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>;
289 // RR Conditional
290 let JJJJJ = 0, Uses = [SR] in
291 def R_CC : InstRR
292 (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI),
293 !strconcat(AsmStr, ".$DDDI\t$Rs1, $Rs2, $Rd"),
294 []>;
295298 }
296299
297300 multiclass ALUlogic subOp, string AsmStr, SDNode OpNode,
301304 [(set GPR:$Rd, (OpNode GPR:$Rs1, HiExt:$imm16))]>;
302305
303306 // Register Register
304 let JJJJJ = 0, DDDI = 0 in
305 def R : InstRR
306 !strconcat(AsmStr, "\t$Rs1, $Rs2, $Rd"),
307 let JJJJJ = 0 in
308 def R : InstRR
309 !strconcat(AsmStr, "$DDDI\t$Rs1, $Rs2, $Rd"),
307310 [(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>;
308 // RR Conditional
309 let JJJJJ = 0, Uses = [SR] in
310 def R_CC : InstRR
311 (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI),
312 !strconcat(AsmStr, ".$DDDI\t$Rs1, $Rs2, $Rd"),
313 []>;
314311 }
315312
316313 // Non flag setting ALU operations
406403 def : Pat<(LanaiSubbF GPR:$Rs1, i32hi16:$imm),
407404 (SUBB_F_I_HI GPR:$Rs1, i32hi16:$imm)>;
408405
409 def : InstAlias<"mov $src, $dst", (ADD_R GPR:$dst, GPR:$src, R0)>;
406 def : InstAlias<"mov $src, $dst", (ADD_R GPR:$dst, GPR:$src, R0, 0)>;
410407
411408 let isAsCheapAsAMove = 1, Rs1 = R0.Num, isCodeGenOnly = 1, H = 1, F = 0,
412409 isReMaterializable = 1 in
715712 !strconcat(AsmStr, "\t$Rs1, $Rs2, %r0"),
716713 [(LanaiSetFlag (i32 GPR:$Rs1), (i32 GPR:$Rs2))]>;
717714 let F = 1, Rd = R0.Num, H = 0, Defs = [SR] in
718 def _RI : InstRI
715 def _RI_LO : InstRI
719716 !strconcat(AsmStr, "\t$Rs1, $imm16, %r0"),
720717 [(LanaiSetFlag (i32 GPR:$Rs1), i32lo16z:$imm16)]>;
721 }
722 let isCodeGenOnly = 1 in {
718 let F = 1, Rd = R0.Num, H = 1, Defs = [SR] in
719 def _RI_HI : InstRI
720 !strconcat(AsmStr, "\t$Rs1, $imm16, %r0"),
721 [(LanaiSetFlag (i32 GPR:$Rs1), i32hi16:$imm16)]>;
722 }
723 let isCodeGenOnly = 1, isCompare = 1 in {
723724 defm SFSUB_F : SF<0b010, "sub.f">;
724725 }
725726
196196 }
197197 // Reg = FrameReg OP Reg
198198 if (MI.getOpcode() == Lanai::ADD_I_LO) {
199 if (HasNegOffset)
200 MI.setDesc(TII->get(Lanai::SUB_R));
201 else
202 MI.setDesc(TII->get(Lanai::ADD_R));
203 } else if (isSPLSOpcode(MI.getOpcode()) || isRMOpcode(MI.getOpcode())) {
199 BuildMI(*MI.getParent(), II, DL,
200 HasNegOffset ? TII->get(Lanai::SUB_R) : TII->get(Lanai::ADD_R),
201 MI.getOperand(0).getReg())
202 .addReg(FrameReg)
203 .addReg(Reg)
204 .addImm(LPCC::ICC_T);
205 MI.eraseFromParent();
206 return;
207 }
208 if (isSPLSOpcode(MI.getOpcode()) || isRMOpcode(MI.getOpcode())) {
204209 MI.setDesc(TII->get(getRRMOpcodeVariant(MI.getOpcode())));
205210 if (HasNegOffset) {
206211 // Change the ALU op (operand 3) from LPAC::ADD (the default) to
+0
-294
lib/Target/Lanai/LanaiSetflagAluCombiner.cpp less more
None //===-- LanaiSetflagAluCombiner.cpp - Pass to combine set flag & ALU ops --===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "Lanai.h"
10 #include "LanaiTargetMachine.h"
11 #include "llvm/ADT/SmallSet.h"
12 #include "llvm/ADT/Statistic.h"
13 #include "llvm/CodeGen/MachineFunctionPass.h"
14 #include "llvm/CodeGen/MachineInstrBuilder.h"
15 #include "llvm/CodeGen/RegisterScavenging.h"
16 #include "llvm/Support/CommandLine.h"
17 #include "llvm/Target/TargetInstrInfo.h"
18
19 using namespace llvm;
20
21 #define DEBUG_TYPE "lanai-setflag-alu-combiner"
22
23 STATISTIC(NumSetflagAluCombined,
24 "Number of SET_FLAG and ALU instructions combined");
25
26 static llvm::cl::opt DisableSetflagAluCombiner(
27 "disable-lanai-setflag-alu-combiner", llvm::cl::init(false),
28 llvm::cl::desc("Do not combine SET_FLAG and ALU operators"),
29 llvm::cl::Hidden);
30
31 namespace llvm {
32 void initializeLanaiSetflagAluCombinerPass(PassRegistry &);
33 } // namespace llvm
34
35 namespace {
36 typedef MachineBasicBlock::iterator MbbIterator;
37 typedef MachineFunction::iterator MfIterator;
38
39 class LanaiSetflagAluCombiner : public MachineFunctionPass {
40 public:
41 static char ID;
42 LanaiSetflagAluCombiner() : MachineFunctionPass(ID) {
43 initializeLanaiSetflagAluCombinerPass(*PassRegistry::getPassRegistry());
44 }
45
46 const char *getPassName() const override {
47 return "Lanai SET_FLAG ALU combiner pass";
48 }
49
50 bool runOnMachineFunction(MachineFunction &F) override;
51
52 MachineFunctionProperties getRequiredProperties() const override {
53 return MachineFunctionProperties().set(
54 MachineFunctionProperties::Property::AllVRegsAllocated);
55 }
56
57 private:
58 bool CombineSetflagAluInBasicBlock(MachineFunction *MF,
59 MachineBasicBlock *BB);
60 };
61 } // namespace
62
63 char LanaiSetflagAluCombiner::ID = 0;
64
65 INITIALIZE_PASS(LanaiSetflagAluCombiner, DEBUG_TYPE,
66 "Lanai SET_FLAG ALU combiner pass", false, false)
67
68 namespace {
69
70 const unsigned kInvalid = -1;
71
72 static unsigned flagSettingOpcodeVariant(unsigned OldOpcode) {
73 switch (OldOpcode) {
74 case Lanai::ADD_I_HI:
75 return Lanai::ADD_F_I_HI;
76 case Lanai::ADD_I_LO:
77 return Lanai::ADD_F_I_LO;
78 case Lanai::ADD_R:
79 return Lanai::ADD_F_R;
80 case Lanai::ADD_R_CC:
81 return Lanai::ADD_F_R_CC;
82 case Lanai::ADDC_I_HI:
83 return Lanai::ADDC_F_I_HI;
84 case Lanai::ADDC_I_LO:
85 return Lanai::ADDC_F_I_LO;
86 case Lanai::ADDC_R:
87 return Lanai::ADDC_F_R;
88 case Lanai::ADDC_R_CC:
89 return Lanai::ADDC_F_R_CC;
90 case Lanai::AND_I_HI:
91 return Lanai::AND_F_I_HI;
92 case Lanai::AND_I_LO:
93 return Lanai::AND_F_I_LO;
94 case Lanai::AND_R:
95 return Lanai::AND_F_R;
96 case Lanai::AND_R_CC:
97 return Lanai::AND_F_R_CC;
98 case Lanai::OR_I_HI:
99 return Lanai::OR_F_I_HI;
100 case Lanai::OR_I_LO:
101 return Lanai::OR_F_I_LO;
102 case Lanai::OR_R:
103 return Lanai::OR_F_R;
104 case Lanai::OR_R_CC:
105 return Lanai::OR_F_R_CC;
106 case Lanai::SL_I:
107 return Lanai::SL_F_I;
108 case Lanai::SRL_R:
109 return Lanai::SRL_F_R;
110 case Lanai::SA_I:
111 return Lanai::SA_F_I;
112 case Lanai::SRA_R:
113 return Lanai::SRA_F_R;
114 case Lanai::SUB_I_HI:
115 return Lanai::SUB_F_I_HI;
116 case Lanai::SUB_I_LO:
117 return Lanai::SUB_F_I_LO;
118 case Lanai::SUB_R:
119 return Lanai::SUB_F_R;
120 case Lanai::SUB_R_CC:
121 return Lanai::SUB_F_R_CC;
122 case Lanai::SUBB_I_HI:
123 return Lanai::SUBB_F_I_HI;
124 case Lanai::SUBB_I_LO:
125 return Lanai::SUBB_F_I_LO;
126 case Lanai::SUBB_R:
127 return Lanai::SUBB_F_R;
128 case Lanai::SUBB_R_CC:
129 return Lanai::SUBB_F_R_CC;
130 case Lanai::XOR_I_HI:
131 return Lanai::XOR_F_I_HI;
132 case Lanai::XOR_I_LO:
133 return Lanai::XOR_F_I_LO;
134 case Lanai::XOR_R:
135 return Lanai::XOR_F_R;
136 case Lanai::XOR_R_CC:
137 return Lanai::XOR_F_R_CC;
138 default:
139 return kInvalid;
140 }
141 }
142
143 // Returns whether opcode corresponds to instruction that sets flags.
144 static bool isFlagSettingInstruction(MbbIterator Instruction) {
145 return Instruction->killsRegister(Lanai::SR);
146 }
147
148 // Return the Conditional Code operand for a given instruction kind. For
149 // example, operand at index 1 of a BRIND_CC instruction is the conditional code
150 // (eq, ne, etc.). Returns -1 if the instruction does not have a conditional
151 // code.
152 static int getCCOperandPosition(unsigned Opcode) {
153 switch (Opcode) {
154 case Lanai::BRIND_CC:
155 case Lanai::BRIND_CCA:
156 case Lanai::BRR:
157 case Lanai::BRCC:
158 case Lanai::SCC:
159 return 1;
160 case Lanai::SELECT:
161 case Lanai::ADDC_F_R_CC:
162 case Lanai::ADDC_R_CC:
163 case Lanai::ADD_F_R_CC:
164 case Lanai::ADD_R_CC:
165 case Lanai::AND_F_R_CC:
166 case Lanai::AND_R_CC:
167 case Lanai::OR_F_R_CC:
168 case Lanai::OR_R_CC:
169 case Lanai::SUBB_F_R_CC:
170 case Lanai::SUBB_R_CC:
171 case Lanai::SUB_F_R_CC:
172 case Lanai::SUB_R_CC:
173 case Lanai::XOR_F_R_CC:
174 case Lanai::XOR_R_CC:
175 return 3;
176 default:
177 return -1;
178 }
179 }
180
181 // Returns true if instruction is a lowered SET_FLAG instruction with 0/R0 as
182 // the first operand and whose conditional code is such that it can be merged
183 // (i.e., EQ, NE, PL and MI).
184 static bool isSuitableSetflag(MbbIterator Instruction, MbbIterator End) {
185 unsigned Opcode = Instruction->getOpcode();
186 if (Opcode == Lanai::SFSUB_F_RI || Opcode == Lanai::SFSUB_F_RR) {
187 const MachineOperand &Operand = Instruction->getOperand(1);
188 if (Operand.isReg() && Operand.getReg() != Lanai::R0)
189 return false;
190 if (Operand.isImm() && Operand.getImm() != 0)
191 return false;
192
193 MbbIterator SCCUserIter = Instruction;
194 while (SCCUserIter != End) {
195 ++SCCUserIter;
196 if (SCCUserIter == End)
197 break;
198 // Skip debug instructions. Debug instructions don't affect codegen.
199 if (SCCUserIter->isDebugValue())
200 continue;
201 // Early exit when encountering flag setting or return instruction.
202 if (isFlagSettingInstruction(SCCUserIter))
203 // Only return true if flags are set post the flag setting instruction
204 // tested or a return is executed.
205 return true;
206 int CCIndex = getCCOperandPosition(SCCUserIter->getOpcode());
207 if (CCIndex != -1) {
208 LPCC::CondCode CC = static_cast(
209 SCCUserIter->getOperand(CCIndex).getImm());
210 // Return false if the flag is used outside of a EQ, NE, PL and MI.
211 if (CC != LPCC::ICC_EQ && CC != LPCC::ICC_NE && CC != LPCC::ICC_PL &&
212 CC != LPCC::ICC_MI)
213 return false;
214 }
215 }
216 }
217
218 return false;
219 }
220
221 // Combines a SET_FLAG instruction comparing a register with 0 and an ALU
222 // operation that sets the same register used in the comparison into a single
223 // flag setting ALU instruction (both instructions combined are removed and new
224 // flag setting ALU operation inserted where ALU instruction was).
225 bool LanaiSetflagAluCombiner::CombineSetflagAluInBasicBlock(
226 MachineFunction *MF, MachineBasicBlock *BB) {
227 bool Modified = false;
228 const TargetInstrInfo *TII =
229 MF->getSubtarget().getInstrInfo();
230
231 MbbIterator SetflagIter = BB->begin();
232 MbbIterator End = BB->end();
233 MbbIterator Begin = BB->begin();
234 while (SetflagIter != End) {
235 bool Replaced = false;
236 if (isSuitableSetflag(SetflagIter, End)) {
237 MbbIterator AluIter = SetflagIter;
238 while (AluIter != Begin) {
239 --AluIter;
240 // Skip debug instructions. Debug instructions don't affect codegen.
241 if (AluIter->isDebugValue())
242 continue;
243 // Early exit when encountering flag setting instruction.
244 if (isFlagSettingInstruction(AluIter))
245 break;
246 // Check that output of AluIter is equal to input of SetflagIter.
247 if (AluIter->getNumOperands() > 1 && AluIter->getOperand(0).isReg() &&
248 (AluIter->getOperand(0).getReg() ==
249 SetflagIter->getOperand(0).getReg())) {
250 unsigned NewOpc = flagSettingOpcodeVariant(AluIter->getOpcode());
251 if (NewOpc == kInvalid)
252 break;
253
254 // Change the ALU instruction to the flag setting variant.
255 AluIter->setDesc(TII->get(NewOpc));
256 AluIter->addImplicitDefUseOperands(*MF);
257
258 Replaced = true;
259 ++NumSetflagAluCombined;
260 break;
261 }
262 }
263 // Erase the setflag instruction if merged.
264 if (Replaced)
265 BB->erase(SetflagIter++);
266 }
267
268 Modified |= Replaced;
269 if (!Replaced)
270 ++SetflagIter;
271 }
272
273 return Modified;
274 }
275
276 // Driver function that iterates over the machine basic building blocks of a
277 // machine function
278 bool LanaiSetflagAluCombiner::runOnMachineFunction(MachineFunction &MF) {
279 if (DisableSetflagAluCombiner)
280 return false;
281
282 bool Modified = false;
283 MfIterator End = MF.end();
284 for (MfIterator MFI = MF.begin(); MFI != End; ++MFI) {
285 Modified |= CombineSetflagAluInBasicBlock(&MF, &*MFI);
286 }
287 return Modified;
288 }
289 } // namespace
290
291 FunctionPass *llvm::createLanaiSetflagAluCombinerPass() {
292 return new LanaiSetflagAluCombiner();
293 }
2727
2828 namespace llvm {
2929 void initializeLanaiMemAluCombinerPass(PassRegistry &);
30 void initializeLanaiSetflagAluCombinerPass(PassRegistry &);
3130 } // namespace llvm
3231
3332 extern "C" void LLVMInitializeLanaiTarget() {
111110 // scheduling pass.
112111 void LanaiPassConfig::addPreSched2() {
113112 addPass(createLanaiMemAluCombinerPass());
114 addPass(createLanaiSetflagAluCombinerPass());
115113 }
2323
2424 // LanaiII - This namespace holds all of the target specific flags that
2525 // instruction info tracks.
26 //
2726 namespace LanaiII {
2827 // Target Operand Flag enum.
2928 enum TOF {
3534 // address.
3635 MO_ABS_HI,
3736 MO_ABS_LO,
38
39 // MO_PIC_BASE_OFFSET - On a symbol operand this indicates that the
40 // immediate should get the value of the symbol minus the PIC base label:
41 // SYMBOL_LABEL - PICBASELABEL
42 MO_PIC_BASE_OFFSET,
43
44 // MO_GOT - On a symbol operand this indicates that the immediate is the
45 // offset to the GOT entry for the symbol name from the base of the GOT.
46 MO_GOT,
47
48 // MO_GOTOFFHI/MO_GOTOFFLO - On a symbol operand this indicates that the
49 // immediate is the offset to the location of the symbol name from the
50 // base of the GOT.
51 MO_GOTOFFHI,
52 MO_GOTOFFLO,
53
54 // MO_GOTPCHI/MO_GOTPCLO - On a symbol operand this indicates that
55 // the immediate is an offset to the GOT entry for the symbol name
56 // from the current code location.
57 MO_GOTPCHI,
58 MO_GOTPCLO,
59
60 // MO_PLT - On a symbol operand this indicates that the immediate is
61 // offset to the PLT entry of symbol name from the current code location.
62 MO_PLT
6337 };
6438 } // namespace LanaiII
6539
+0
-170
test/CodeGen/Lanai/combined_alu_setcc.ll less more
None ; RUN: llc < %s -march=lanai | FileCheck %s
1
2 ; Test the alu setcc combiner.
3
4 ; TODO: Enhance combiner to handle this case. This expands into:
5 ; sub %r7, %r6, %r3
6 ; sub.f %r7, %r6, %r0
7 ; sel.eq %r18, %r3, %rv
8 ; This is different from the pattern currently matched. If the lowered form had
9 ; been sub.f %r3, 0, %r0 then it would have matched.
10
11 ; Function Attrs: norecurse nounwind readnone
12 define i32 @test0a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
13 entry:
14 %sub = sub i32 %b, %a
15 %cmp = icmp eq i32 %sub, 0
16 %cond = select i1 %cmp, i32 %c, i32 %sub
17 ret i32 %cond
18 }
19 ; CHECK-LABEL: test0a
20 ; CHECK: sub.f %r7
21 ; CHECK: sel.eq
22
23 ; Function Attrs: norecurse nounwind readnone
24 define i32 @test0b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
25 entry:
26 %cmp = icmp eq i32 %b, %a
27 %cond = select i1 %cmp, i32 %c, i32 %b
28 ret i32 %cond
29 }
30 ; CHECK-LABEL: test0b
31 ; CHECK: sub.f %r7, %r6, %r0
32 ; CHECK-NEXT: sel.eq
33
34 ; Function Attrs: norecurse nounwind readnone
35 define i32 @test1a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
36 entry:
37 %sub = sub i32 %b, %a
38 %cmp = icmp slt i32 %sub, 0
39 %cond = select i1 %cmp, i32 %c, i32 %d
40 ret i32 %cond
41 }
42 ; CHECK-LABEL: test1a
43 ; CHECK: sub.f %r7, %r6
44 ; CHECK-NEXT: sel.mi
45
46 ; Function Attrs: norecurse nounwind readnone
47 define i32 @test1b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
48 entry:
49 %sub = sub i32 %b, %a
50 %cmp = icmp slt i32 %sub, 0
51 %cond = select i1 %cmp, i32 %c, i32 %d
52 ret i32 %cond
53 }
54 ; CHECK-LABEL: test1b
55 ; CHECK: sub.f %r7, %r6
56 ; CHECK-NEXT: sel.mi
57
58 ; Function Attrs: norecurse nounwind readnone
59 define i32 @test2a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
60 entry:
61 %sub = sub i32 %b, %a
62 %cmp = icmp sgt i32 %sub, -1
63 %cond = select i1 %cmp, i32 %c, i32 %d
64 ret i32 %cond
65 }
66 ; CHECK-LABEL: test2a
67 ; CHECK: sub.f %r7, %r6
68 ; CHECK: sel.pl
69
70 ; Function Attrs: norecurse nounwind readnone
71 define i32 @test2b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
72 entry:
73 %sub = sub i32 %b, %a
74 %cmp = icmp sgt i32 %sub, -1
75 %cond = select i1 %cmp, i32 %c, i32 %d
76 ret i32 %cond
77 }
78 ; CHECK-LABEL: test2b
79 ; CHECK: sub.f %r7, %r6
80 ; CHECK: sel.pl
81
82 ; Function Attrs: norecurse nounwind readnone
83 define i32 @test3(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
84 entry:
85 %sub = sub i32 %b, %a
86 %cmp = icmp slt i32 %sub, 1
87 %cond = select i1 %cmp, i32 %c, i32 %d
88 ret i32 %cond
89 }
90
91 ; Function Attrs: norecurse nounwind readnone
92 define i32 @test4(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
93 entry:
94 %cmp = icmp ne i32 %a, 0
95 %cmp1 = icmp ult i32 %a, %b
96 %or.cond = and i1 %cmp, %cmp1
97 br i1 %or.cond, label %return, label %if.end
98
99 if.end: ; preds = %entry
100 %cmp2 = icmp ne i32 %b, 0
101 %cmp4 = icmp ult i32 %b, %c
102 %or.cond29 = and i1 %cmp2, %cmp4
103 br i1 %or.cond29, label %return, label %if.end6
104
105 if.end6: ; preds = %if.end
106 %cmp7 = icmp ne i32 %c, 0
107 %cmp9 = icmp ult i32 %c, %d
108 %or.cond30 = and i1 %cmp7, %cmp9
109 br i1 %or.cond30, label %return, label %if.end11
110
111 if.end11: ; preds = %if.end6
112 %cmp12 = icmp ne i32 %d, 0
113 %cmp14 = icmp ult i32 %d, %a
114 %or.cond31 = and i1 %cmp12, %cmp14
115 %b. = select i1 %or.cond31, i32 %b, i32 21
116 ret i32 %b.
117
118 return: ; preds = %if.end6, %if.end, %entry
119 %retval.0 = phi i32 [ %c, %entry ], [ %d, %if.end ], [ %a, %if.end6 ]
120 ret i32 %retval.0
121 }
122 ; CHECK-LABEL: test4
123 ; TODO: Re-enable test. This test is disabled post making the combiner more
124 ; conservative.
125 ; DISABLED_CHECK: and.f
126
127 ; Test to avoid incorrect fusing that spans across basic blocks
128 @a = global i32 -1, align 4
129 @b = global i32 0, align 4
130
131 ; Function Attrs: nounwind
132 define void @testBB() {
133 entry:
134 %0 = load i32, i32* @a, align 4, !tbaa !1
135 %1 = load i32, i32* @b, align 4, !tbaa !1
136 %sub.i = sub i32 %1, %0
137 %tobool = icmp sgt i32 %sub.i, -1
138 br i1 %tobool, label %if.end, label %if.then
139
140 if.then: ; preds = %entry
141 %call1 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
142 br label %while.body
143
144 while.body: ; preds = %if.then, %while.body
145 br label %while.body
146
147 if.end: ; preds = %entry
148 %cmp.i = icmp slt i32 %sub.i, 1
149 br i1 %cmp.i, label %if.then4, label %if.end7
150
151 if.then4: ; preds = %if.end
152 %call5 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
153 br label %while.body6
154
155 while.body6: ; preds = %if.then4, %while.body6
156 br label %while.body6
157
158 if.end7: ; preds = %if.end
159 ret void
160 }
161
162 declare i32 @g(...)
163 ; CHECK-LABEL: testBB
164 ; CHECK: sub.f {{.*}}, %r0
165
166 !1 = !{!2, !2, i64 0}
167 !2 = !{!"int", !3, i64 0}
168 !3 = !{!"omnipotent char", !4, i64 0}
169 !4 = !{!"Simple C/C++ TBAA"}
0 ; RUN: llc < %s -mtriple=lanai | FileCheck %s
1
2 define i32 @f(i32 inreg %a, i32 inreg %b) nounwind ssp {
3 entry:
4 ; CHECK-LABEL: f:
5 ; CHECK: sub.f %r6, %r7, [[IN:%.*]]
6 ; CHECK: sel.gt [[IN]], %r0, %rv
7 %cmp = icmp sgt i32 %a, %b
8 %sub = sub nsw i32 %a, %b
9 %sub. = select i1 %cmp, i32 %sub, i32 0
10 ret i32 %sub.
11 }
12
13 define i32 @g(i32 inreg %a, i32 inreg %b) nounwind ssp {
14 entry:
15 ; CHECK-LABEL: g:
16 ; CHECK: sub.f %r7, %r6, [[IN:%.*]]
17 ; CHECK: sel.lt [[IN]], %r0, %rv
18 %cmp = icmp slt i32 %a, %b
19 %sub = sub nsw i32 %b, %a
20 %sub. = select i1 %cmp, i32 %sub, i32 0
21 ret i32 %sub.
22 }
23
24 define i32 @h(i32 inreg %a, i32 inreg %b) nounwind ssp {
25 entry:
26 ; CHECK-LABEL: h:
27 ; CHECK: sub.f %r6, 0x3, [[IN:%.*]]
28 ; CHECK: sel.gt [[IN]], %r7, %rv
29 %cmp = icmp sgt i32 %a, 3
30 %sub = sub nsw i32 %a, 3
31 %sub. = select i1 %cmp, i32 %sub, i32 %b
32 ret i32 %sub.
33 }
34
35 define i32 @i(i32 inreg %a, i32 inreg %b) nounwind readnone ssp {
36 entry:
37 ; CHECK-LABEL: i:
38 ; CHECK: sub.f %r7, %r6, [[IN:%.*]]
39 ; CHECK: sel.ult [[IN]], %r0, %rv
40 %cmp = icmp ult i32 %a, %b
41 %sub = sub i32 %b, %a
42 %sub. = select i1 %cmp, i32 %sub, i32 0
43 ret i32 %sub.
44 }
45 ; If SR is live-out, we can't remove cmp if there exists a swapped sub.
46 define i32 @j(i32 inreg %a, i32 inreg %b) nounwind {
47 entry:
48 ; CHECK-LABEL: j:
49 ; CHECK: sub.f %r7, %r6, %r0
50 ; CHECK: sub %r6, %r7, %rv
51 %cmp = icmp eq i32 %b, %a
52 %sub = sub nsw i32 %a, %b
53 br i1 %cmp, label %if.then, label %if.else
54
55 if.then:
56 %cmp2 = icmp sgt i32 %b, %a
57 %sel = select i1 %cmp2, i32 %sub, i32 %a
58 ret i32 %sel
59
60 if.else:
61 ret i32 %sub
62 }
63
64 declare void @abort()
65 declare void @exit(i32)
66 @t = common global i32 0
67
68 ; If the comparison uses the C bit (signed overflow/underflow), we can't
69 ; omit the comparison.
70 define i32 @cmp_ult0(i32 inreg %a, i32 inreg %b, i32 inreg %x, i32 inreg %y) {
71 entry:
72 ; CHECK-LABEL: cmp_ult0
73 ; CHECK: sub {{.*}}, 0x11, [[IN:%.*]]
74 ; CHECK: sub.f [[IN]], 0x0, %r0
75 %load = load i32, i32* @t, align 4
76 %sub = sub i32 %load, 17
77 %cmp = icmp ult i32 %sub, 0
78 br i1 %cmp, label %if.then, label %if.else
79
80 if.then:
81 call void @abort()
82 unreachable
83
84 if.else:
85 call void @exit(i32 0)
86 unreachable
87 }
88
89 ; Same for the V bit.
90 ; TODO: add test that exercises V bit individually (VC/VS).
91 define i32 @cmp_gt0(i32 inreg %a, i32 inreg %b, i32 inreg %x, i32 inreg %y) {
92 entry:
93 ; CHECK-LABEL: cmp_gt0
94 ; CHECK: sub {{.*}}, 0x11, [[IN:%.*]]
95 ; CHECK: sub.f [[IN]], 0x1, %r0
96 %load = load i32, i32* @t, align 4
97 %sub = sub i32 %load, 17
98 %cmp = icmp sgt i32 %sub, 0
99 br i1 %cmp, label %if.then, label %if.else
100
101 if.then:
102 call void @abort()
103 unreachable
104
105 if.else:
106 call void @exit(i32 0)
107 unreachable
108 }
0 if not 'Lanai' in config.root.targets:
1 config.unsupported = True
0 # RUN: llc -run-pass=peephole-opts %s -o /dev/null 2>&1 | FileCheck %s
1
2 # Test the compare fold peephole.
3
4 # CHECK-LABEL: name: test0a
5 # TODO: Enhance combiner to handle this case. This expands into:
6 # sub %r7, %r6, %r3
7 # sub.f %r7, %r6, %r0
8 # sel.eq %r18, %r3, %rv
9 # This is different from the pattern currently matched. If the lowered form had
10 # been sub.f %r3, 0, %r0 then it would have matched.
11
12 # CHECK-LABEL: name: test1a
13 # CHECK: [[IN1:%.*]] = COPY %r7
14 # CHECK: [[IN2:%.*]] = COPY %r6
15 # CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
16
17 # CHECK-LABEL: name: test1b
18 # CHECK: [[IN1:%.*]] = COPY %r7
19 # CHECK: [[IN2:%.*]] = COPY %r6
20 # CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
21
22 # CHECK-LABEL: name: test2a
23 # CHECK: [[IN1:%.*]] = COPY %r7
24 # CHECK: [[IN2:%.*]] = COPY %r6
25 # CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
26
27 # CHECK-LABEL: name: test2b
28 # CHECK: [[IN1:%.*]] = COPY %r7
29 # CHECK: [[IN2:%.*]] = COPY %r6
30 # CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
31
32 # CHECK-LABEL: name: test3
33 # CHECK: AND_F_R
34 # CHECK: AND_F_R
35 # CHECK: AND_F_R
36
37 --- |
38 target datalayout = "E-m:e-p:32:32-i64:64-a:0:32-n32-S64"
39 target triple = "lanai-unknown-unknown"
40
41 @a = global i32 -1, align 4
42 @b = global i32 0, align 4
43
44 define i32 @test0a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
45 entry:
46 %sub = sub i32 %b, %a
47 %cmp = icmp eq i32 %sub, 0
48 %cond = select i1 %cmp, i32 %c, i32 %sub
49 ret i32 %cond
50 }
51
52 define i32 @test0b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
53 entry:
54 %cmp = icmp eq i32 %b, %a
55 %cond = select i1 %cmp, i32 %c, i32 %b
56 ret i32 %cond
57 }
58
59 define i32 @test1a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
60 entry:
61 %sub = sub i32 %b, %a
62 %cmp = icmp slt i32 %sub, 0
63 %cond = select i1 %cmp, i32 %c, i32 %d
64 ret i32 %cond
65 }
66
67 define i32 @test1b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
68 entry:
69 %sub = sub i32 %b, %a
70 %cmp = icmp slt i32 %sub, 0
71 %cond = select i1 %cmp, i32 %c, i32 %d
72 ret i32 %cond
73 }
74
75 define i32 @test2a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
76 entry:
77 %sub = sub i32 %b, %a
78 %cmp = icmp sgt i32 %sub, -1
79 %cond = select i1 %cmp, i32 %c, i32 %d
80 ret i32 %cond
81 }
82
83 define i32 @test2b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
84 entry:
85 %sub = sub i32 %b, %a
86 %cmp = icmp sgt i32 %sub, -1
87 %cond = select i1 %cmp, i32 %c, i32 %d
88 ret i32 %cond
89 }
90
91 define i32 @test3(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
92 entry:
93 %sub = sub i32 %b, %a
94 %cmp = icmp slt i32 %sub, 1
95 %cond = select i1 %cmp, i32 %c, i32 %d
96 ret i32 %cond
97 }
98
99 define i32 @test4(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
100 entry:
101 %cmp = icmp ne i32 %a, 0
102 %cmp1 = icmp ult i32 %a, %b
103 %or.cond = and i1 %cmp, %cmp1
104 br i1 %or.cond, label %return, label %if.end
105
106 if.end: ; preds = %entry
107 %cmp2 = icmp ne i32 %b, 0
108 %cmp4 = icmp ult i32 %b, %c
109 %or.cond29 = and i1 %cmp2, %cmp4
110 br i1 %or.cond29, label %return, label %if.end6
111
112 if.end6: ; preds = %if.end
113 %cmp7 = icmp ne i32 %c, 0
114 %cmp9 = icmp ult i32 %c, %d
115 %or.cond30 = and i1 %cmp7, %cmp9
116 br i1 %or.cond30, label %return, label %if.end11
117
118 if.end11: ; preds = %if.end6
119 %cmp12 = icmp ne i32 %d, 0
120 %cmp14 = icmp ult i32 %d, %a
121 %or.cond31 = and i1 %cmp12, %cmp14
122 %b. = select i1 %or.cond31, i32 %b, i32 21
123 ret i32 %b.
124
125 return: ; preds = %if.end6, %if.end, %entry
126 %retval.0 = phi i32 [ %c, %entry ], [ %d, %if.end ], [ %a, %if.end6 ]
127 ret i32 %retval.0
128 }
129
130 define void @testBB() {
131 entry:
132 %0 = load i32, i32* @a, align 4, !tbaa !0
133 %1 = load i32, i32* @b, align 4, !tbaa !0
134 %sub.i = sub i32 %1, %0
135 %tobool = icmp sgt i32 %sub.i, -1
136 br i1 %tobool, label %if.end, label %if.then
137
138 if.then: ; preds = %entry
139 %call1 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
140 br label %while.body
141
142 while.body: ; preds = %while.body, %if.then
143 br label %while.body
144
145 if.end: ; preds = %entry
146 %cmp.i = icmp slt i32 %sub.i, 1
147 br i1 %cmp.i, label %if.then4, label %if.end7
148
149 if.then4: ; preds = %if.end
150 %call5 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
151 br label %while.body6
152
153 while.body6: ; preds = %while.body6, %if.then4
154 br label %while.body6
155
156 if.end7: ; preds = %if.end
157 ret void
158 }
159
160 declare i32 @g(...)
161
162 ; Function Attrs: nounwind
163 declare void @llvm.stackprotector(i8*, i8**) #0
164
165 attributes #0 = { nounwind }
166
167 !0 = !{!1, !1, i64 0}
168 !1 = !{!"int", !2, i64 0}
169 !2 = !{!"omnipotent char", !3, i64 0}
170 !3 = !{!"Simple C/C++ TBAA"}
171
172 ...
173 ---
174 name: test0a
175 alignment: 2
176 exposesReturnsTwice: false
177 hasInlineAsm: false
178 allVRegsAllocated: false
179 isSSA: true
180 tracksRegLiveness: true
181 tracksSubRegLiveness: false
182 registers:
183 - { id: 0, class: gpr }
184 - { id: 1, class: gpr }
185 - { id: 2, class: gpr }
186 - { id: 3, class: gpr }
187 - { id: 4, class: gpr }
188 - { id: 5, class: gpr }
189 liveins:
190 - { reg: '%r6', virtual-reg: '%0' }
191 - { reg: '%r7', virtual-reg: '%1' }
192 - { reg: '%r18', virtual-reg: '%2' }
193 frameInfo:
194 isFrameAddressTaken: false
195 isReturnAddressTaken: false
196 hasStackMap: false
197 hasPatchPoint: false
198 stackSize: 0
199 offsetAdjustment: 0
200 maxAlignment: 0
201 adjustsStack: false
202 hasCalls: false
203 maxCallFrameSize: 0
204 hasOpaqueSPAdjustment: false
205 hasVAStart: false
206 hasMustTailInVarArgFunc: false
207 body: |
208 bb.0.entry:
209 liveins: %r6, %r7, %r18
210
211 %2 = COPY %r18
212 %1 = COPY %r7
213 %0 = COPY %r6
214 %4 = SUB_R %1, %0, 0
215 SFSUB_F_RI_LO %4, 0, implicit-def %sr
216 %5 = SELECT %2, %4, 7, implicit %sr
217 %rv = COPY %5
218 RET implicit %rca, implicit %rv
219
220 ...
221 ---
222 name: test0b
223 alignment: 2
224 exposesReturnsTwice: false
225 hasInlineAsm: false
226 allVRegsAllocated: false
227 isSSA: true
228 tracksRegLiveness: true
229 tracksSubRegLiveness: false
230 registers:
231 - { id: 0, class: gpr }
232 - { id: 1, class: gpr }
233 - { id: 2, class: gpr }
234 - { id: 3, class: gpr }
235 - { id: 4, class: gpr }
236 liveins:
237 - { reg: '%r6', virtual-reg: '%0' }
238 - { reg: '%r7', virtual-reg: '%1' }
239 - { reg: '%r18', virtual-reg: '%2' }
240 frameInfo:
241 isFrameAddressTaken: false
242 isReturnAddressTaken: false
243 hasStackMap: false
244 hasPatchPoint: false
245 stackSize: 0
246 offsetAdjustment: 0
247 maxAlignment: 0
248 adjustsStack: false
249 hasCalls: false
250 maxCallFrameSize: 0
251 hasOpaqueSPAdjustment: false
252 hasVAStart: false
253 hasMustTailInVarArgFunc: false
254 body: |
255 bb.0.entry:
256 liveins: %r6, %r7, %r18
257
258 %2 = COPY %r18
259 %1 = COPY %r7
260 %0 = COPY %r6
261 SFSUB_F_RR %1, %0, implicit-def %sr
262 %4 = SELECT %2, %1, 7, implicit %sr
263 %rv = COPY %4
264 RET implicit %rca, implicit %rv
265
266 ...
267 ---
268 name: test1a
269 alignment: 2
270 exposesReturnsTwice: false
271 hasInlineAsm: false
272 allVRegsAllocated: false
273 isSSA: true
274 tracksRegLiveness: true
275 tracksSubRegLiveness: false
276 registers:
277 - { id: 0, class: gpr }
278 - { id: 1, class: gpr }
279 - { id: 2, class: gpr }
280 - { id: 3, class: gpr }
281 - { id: 4, class: gpr }
282 - { id: 5, class: gpr }
283 liveins:
284 - { reg: '%r6', virtual-reg: '%0' }
285 - { reg: '%r7', virtual-reg: '%1' }
286 - { reg: '%r18', virtual-reg: '%2' }
287 - { reg: '%r19', virtual-reg: '%3' }
288 frameInfo:
289 isFrameAddressTaken: false
290 isReturnAddressTaken: false
291 hasStackMap: false
292 hasPatchPoint: false
293 stackSize: 0
294 offsetAdjustment: 0
295 maxAlignment: 0
296 adjustsStack: false
297 hasCalls: false
298 maxCallFrameSize: 0
299 hasOpaqueSPAdjustment: false
300 hasVAStart: false
301 hasMustTailInVarArgFunc: false
302 body: |
303 bb.0.entry:
304 liveins: %r6, %r7, %r18, %r19
305
306 %3 = COPY %r19
307 %2 = COPY %r18
308 %1 = COPY %r7
309 %0 = COPY %r6
310 %4 = SUB_R %1, %0, 0
311 SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
312 %5 = SELECT %2, %3, 11, implicit %sr
313 %rv = COPY %5
314 RET implicit %rca, implicit %rv
315
316 ...
317 ---
318 name: test1b
319 alignment: 2
320 exposesReturnsTwice: false
321 hasInlineAsm: false
322 allVRegsAllocated: false
323 isSSA: true
324 tracksRegLiveness: true
325 tracksSubRegLiveness: false
326 registers:
327 - { id: 0, class: gpr }
328 - { id: 1, class: gpr }
329 - { id: 2, class: gpr }
330 - { id: 3, class: gpr }
331 - { id: 4, class: gpr }
332 - { id: 5, class: gpr }
333 liveins:
334 - { reg: '%r6', virtual-reg: '%0' }
335 - { reg: '%r7', virtual-reg: '%1' }
336 - { reg: '%r18', virtual-reg: '%2' }
337 - { reg: '%r19', virtual-reg: '%3' }
338 frameInfo:
339 isFrameAddressTaken: false
340 isReturnAddressTaken: false
341 hasStackMap: false
342 hasPatchPoint: false
343 stackSize: 0
344 offsetAdjustment: 0
345 maxAlignment: 0
346 adjustsStack: false
347 hasCalls: false
348 maxCallFrameSize: 0
349 hasOpaqueSPAdjustment: false
350 hasVAStart: false
351 hasMustTailInVarArgFunc: false
352 body: |
353 bb.0.entry:
354 liveins: %r6, %r7, %r18, %r19
355
356 %3 = COPY %r19
357 %2 = COPY %r18
358 %1 = COPY %r7
359 %0 = COPY %r6
360 %4 = SUB_R %1, %0, 0
361 SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
362 %5 = SELECT %2, %3, 11, implicit %sr
363 %rv = COPY %5
364 RET implicit %rca, implicit %rv
365
366 ...
367 ---
368 name: test2a
369 alignment: 2
370 exposesReturnsTwice: false
371 hasInlineAsm: false
372 allVRegsAllocated: false
373 isSSA: true
374 tracksRegLiveness: true
375 tracksSubRegLiveness: false
376 registers:
377 - { id: 0, class: gpr }
378 - { id: 1, class: gpr }
379 - { id: 2, class: gpr }
380 - { id: 3, class: gpr }
381 - { id: 4, class: gpr }
382 - { id: 5, class: gpr }
383 liveins:
384 - { reg: '%r6', virtual-reg: '%0' }
385 - { reg: '%r7', virtual-reg: '%1' }
386 - { reg: '%r18', virtual-reg: '%2' }
387 - { reg: '%r19', virtual-reg: '%3' }
388 frameInfo:
389 isFrameAddressTaken: false
390 isReturnAddressTaken: false
391 hasStackMap: false
392 hasPatchPoint: false
393 stackSize: 0
394 offsetAdjustment: 0
395 maxAlignment: 0
396 adjustsStack: false
397 hasCalls: false
398 maxCallFrameSize: 0
399 hasOpaqueSPAdjustment: false
400 hasVAStart: false
401 hasMustTailInVarArgFunc: false
402 body: |
403 bb.0.entry:
404 liveins: %r6, %r7, %r18, %r19
405
406 %3 = COPY %r19
407 %2 = COPY %r18
408 %1 = COPY %r7
409 %0 = COPY %r6
410 %4 = SUB_R %1, %0, 0
411 SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
412 %5 = SELECT %2, %3, 10, implicit %sr
413 %rv = COPY %5
414 RET implicit %rca, implicit %rv
415
416 ...
417 ---
418 name: test2b
419 alignment: 2
420 exposesReturnsTwice: false
421 hasInlineAsm: false
422 allVRegsAllocated: false
423 isSSA: true
424 tracksRegLiveness: true
425 tracksSubRegLiveness: false
426 registers:
427 - { id: 0, class: gpr }
428 - { id: 1, class: gpr }
429 - { id: 2, class: gpr }
430 - { id: 3, class: gpr }
431 - { id: 4, class: gpr }
432 - { id: 5, class: gpr }
433 liveins:
434 - { reg: '%r6', virtual-reg: '%0' }
435 - { reg: '%r7', virtual-reg: '%1' }
436 - { reg: '%r18', virtual-reg: '%2' }
437 - { reg: '%r19', virtual-reg: '%3' }
438 frameInfo:
439 isFrameAddressTaken: false
440 isReturnAddressTaken: false
441 hasStackMap: false
442 hasPatchPoint: false
443 stackSize: 0
444 offsetAdjustment: 0
445 maxAlignment: 0
446 adjustsStack: false
447 hasCalls: false
448 maxCallFrameSize: 0
449 hasOpaqueSPAdjustment: false
450 hasVAStart: false
451 hasMustTailInVarArgFunc: false
452 body: |
453 bb.0.entry:
454 liveins: %r6, %r7, %r18, %r19
455
456 %3 = COPY %r19
457 %2 = COPY %r18
458 %1 = COPY %r7
459 %0 = COPY %r6
460 %4 = SUB_R %1, %0, 0
461 SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
462 %5 = SELECT %2, %3, 10, implicit %sr
463 %rv = COPY %5
464 RET implicit %rca, implicit %rv
465
466 ...
467 ---
468 name: test3
469 alignment: 2
470 exposesReturnsTwice: false
471 hasInlineAsm: false
472 allVRegsAllocated: false
473 isSSA: true
474 tracksRegLiveness: true
475 tracksSubRegLiveness: false
476 registers:
477 - { id: 0, class: gpr }
478 - { id: 1, class: gpr }
479 - { id: 2, class: gpr }
480 - { id: 3, class: gpr }
481 - { id: 4, class: gpr }
482 - { id: 5, class: gpr }
483 liveins:
484 - { reg: '%r6', virtual-reg: '%0' }
485 - { reg: '%r7', virtual-reg: '%1' }
486 - { reg: '%r18', virtual-reg: '%2' }
487 - { reg: '%r19', virtual-reg: '%3' }
488 frameInfo:
489 isFrameAddressTaken: false
490 isReturnAddressTaken: false
491 hasStackMap: false
492 hasPatchPoint: false
493 stackSize: 0
494 offsetAdjustment: 0
495 maxAlignment: 0
496 adjustsStack: false
497 hasCalls: false
498 maxCallFrameSize: 0
499 hasOpaqueSPAdjustment: false
500 hasVAStart: false
501 hasMustTailInVarArgFunc: false
502 body: |
503 bb.0.entry:
504 liveins: %r6, %r7, %r18, %r19
505
506 %3 = COPY %r19
507 %2 = COPY %r18
508 %1 = COPY %r7
509 %0 = COPY %r6
510 %4 = SUB_R %1, %0, 0
511 SFSUB_F_RI_LO killed %4, 1, implicit-def %sr
512 %5 = SELECT %2, %3, 13, implicit %sr
513 %rv = COPY %5
514 RET implicit %rca, implicit %rv
515
516 ...
517 ---
518 name: test4
519 alignment: 2
520 exposesReturnsTwice: false
521 hasInlineAsm: false
522 allVRegsAllocated: false
523 isSSA: true
524 tracksRegLiveness: true
525 tracksSubRegLiveness: false
526 registers:
527 - { id: 0, class: gpr }
528 - { id: 1, class: gpr }
529 - { id: 2, class: gpr }
530 - { id: 3, class: gpr }
531 - { id: 4, class: gpr }
532 - { id: 5, class: gpr }
533 - { id: 6, class: gpr }
534 - { id: 7, class: gpr }
535 - { id: 8, class: gpr }
536 - { id: 9, class: gpr }
537 - { id: 10, class: gpr }
538 - { id: 11, class: gpr }
539 - { id: 12, class: gpr }
540 - { id: 13, class: gpr }
541 - { id: 14, class: gpr }
542 - { id: 15, class: gpr }
543 - { id: 16, class: gpr }
544 - { id: 17, class: gpr }
545 - { id: 18, class: gpr }
546 - { id: 19, class: gpr }
547 - { id: 20, class: gpr }
548 - { id: 21, class: gpr }
549 - { id: 22, class: gpr }
550 liveins:
551 - { reg: '%r6', virtual-reg: '%1' }
552 - { reg: '%r7', virtual-reg: '%2' }
553 - { reg: '%r18', virtual-reg: '%3' }
554 - { reg: '%r19', virtual-reg: '%4' }
555 frameInfo:
556 isFrameAddressTaken: false
557 isReturnAddressTaken: false
558 hasStackMap: false
559 hasPatchPoint: false
560 stackSize: 0
561 offsetAdjustment: 0
562 maxAlignment: 0
563 adjustsStack: false
564 hasCalls: false
565 maxCallFrameSize: 0
566 hasOpaqueSPAdjustment: false
567 hasVAStart: false
568 hasMustTailInVarArgFunc: false
569 body: |
570 bb.0.entry:
571 successors: %bb.4.return, %bb.1.if.end
572 liveins: %r6, %r7, %r18, %r19
573
574 %4 = COPY %r19
575 %3 = COPY %r18
576 %2 = COPY %r7
577 %1 = COPY %r6
578 SFSUB_F_RI_LO %1, 0, implicit-def %sr
579 %5 = SCC 6, implicit %sr
580 SFSUB_F_RR %1, %2, implicit-def %sr
581 %6 = SCC 4, implicit %sr
582 %7 = AND_R killed %5, killed %6, 0
583 %8 = SLI 1
584 %9 = AND_R killed %7, %8, 0
585 SFSUB_F_RI_LO killed %9, 0, implicit-def %sr
586 BRCC %bb.4.return, 6, implicit %sr
587 BT %bb.1.if.end
588
589 bb.1.if.end:
590 successors: %bb.4.return, %bb.2.if.end6
591
592 SFSUB_F_RI_LO %2, 0, implicit-def %sr
593 %10 = SCC 6, implicit %sr
594 SFSUB_F_RR %2, %3, implicit-def %sr
595 %11 = SCC 4, implicit %sr
596 %12 = AND_R killed %10, killed %11, 0
597 %14 = AND_R killed %12, %8, 0
598 SFSUB_F_RI_LO killed %14, 0, implicit-def %sr
599 BRCC %bb.4.return, 6, implicit %sr
600 BT %bb.2.if.end6
601
602 bb.2.if.end6:
603 successors: %bb.4.return, %bb.3.if.end11
604
605 SFSUB_F_RI_LO %3, 0, implicit-def %sr
606 %15 = SCC 6, implicit %sr
607 SFSUB_F_RR %3, %4, implicit-def %sr
608 %16 = SCC 4, implicit %sr
609 %17 = AND_R killed %15, killed %16, 0
610 %18 = SLI 1
611 %19 = AND_R killed %17, killed %18, 0
612 SFSUB_F_RI_LO killed %19, 0, implicit-def %sr
613 BRCC %bb.4.return, 6, implicit %sr
614 BT %bb.3.if.end11
615
616 bb.3.if.end11:
617 %20 = SLI 21
618 SFSUB_F_RR %4, %1, implicit-def %sr
619 %21 = SELECT %2, %20, 4, implicit %sr
620 SFSUB_F_RI_LO %4, 0, implicit-def %sr
621 %22 = SELECT killed %21, %20, 6, implicit %sr
622 %rv = COPY %22
623 RET implicit %rca, implicit %rv
624
625 bb.4.return:
626 %0 = PHI %3, %bb.0.entry, %4, %bb.1.if.end, %1, %bb.2.if.end6
627 %rv = COPY %0
628 RET implicit %rca, implicit %rv
629
630 ...
631 ---
632 name: testBB
633 alignment: 2
634 exposesReturnsTwice: false
635 hasInlineAsm: false
636 allVRegsAllocated: false
637 isSSA: true
638 tracksRegLiveness: true
639 tracksSubRegLiveness: false
640 registers:
641 - { id: 0, class: gpr }
642 - { id: 1, class: gpr }
643 - { id: 2, class: gpr }
644 - { id: 3, class: gpr }
645 - { id: 4, class: gpr }
646 - { id: 5, class: gpr }
647 - { id: 6, class: gpr }
648 - { id: 7, class: gpr }
649 - { id: 8, class: gpr }
650 frameInfo:
651 isFrameAddressTaken: false
652 isReturnAddressTaken: false
653 hasStackMap: false
654 hasPatchPoint: false
655 stackSize: 0
656 offsetAdjustment: 0
657 maxAlignment: 0
658 adjustsStack: false
659 hasCalls: true
660 maxCallFrameSize: 0
661 hasOpaqueSPAdjustment: false
662 hasVAStart: false
663 hasMustTailInVarArgFunc: false
664 body: |
665 bb.0.entry:
666 successors: %bb.3.if.end, %bb.1.if.then
667
668 %1 = MOVHI target-flags(lanai-hi) @a
669 %2 = OR_I_LO killed %1, target-flags(lanai-lo) @a
670 %3 = LDW_RI killed %2, 0, 0 :: (load 4 from @a, !tbaa !0)
671 %4 = MOVHI target-flags(lanai-hi) @b
672 %5 = OR_I_LO killed %4, target-flags(lanai-lo) @b
673 %6 = LDW_RI killed %5, 0, 0 :: (load 4 from @b, !tbaa !0)
674 %0 = SUB_R killed %6, killed %3, 0
675 SFSUB_F_RI_LO %0, 0, implicit-def %sr
676 BRCC %bb.3.if.end, 10, implicit %sr
677 BT %bb.1.if.then
678
679 bb.1.if.then:
680 successors: %bb.2.while.body
681
682 ADJCALLSTACKDOWN 0, implicit-def dead %sp, implicit %sp
683 CALL @g, csr, implicit-def dead %rca, implicit %sp, implicit-def %sp, implicit-def %rv
684 ADJCALLSTACKUP 0, 0, implicit-def dead %sp, implicit %sp
685
686 bb.2.while.body:
687 successors: %bb.2.while.body
688
689 BT %bb.2.while.body
690
691 bb.3.if.end:
692 successors: %bb.4.if.then4, %bb.6.if.end7
693 liveins: %sr
694
695 BRCC %bb.6.if.end7, 14, implicit %sr
696 BT %bb.4.if.then4
697
698 bb.4.if.then4:
699 successors: %bb.5.while.body6
700
701 ADJCALLSTACKDOWN 0, implicit-def dead %sp, implicit %sp
702 CALL @g, csr, implicit-def dead %rca, implicit %sp, implicit-def %sp, implicit-def %rv
703 ADJCALLSTACKUP 0, 0, implicit-def dead %sp, implicit %sp
704
705 bb.5.while.body6:
706 successors: %bb.5.while.body6
707
708 BT %bb.5.while.body6
709
710 bb.6.if.end7:
711 RET implicit %rca
712
713 ...
1111 ! CHECK: 0x0a,0xc6,0x12,0x34
1212 add.f %r17, 0x12340000, %r21
1313 ! CHECK: 0x0a,0xc7,0x12,0x34
14 add %r17, %r18, %r21
14 add.t %r17, %r18, %r21
1515 ! CHECK: 0xca,0xc4,0x90,0x00
16 add.f %r17, %r18, %r21
16 add.f.t %r17, %r18, %r21
1717 ! CHECK: 0xca,0xc6,0x90,0x00
18 addc %r17, %r18, %r21
18 addc.t %r17, %r18, %r21
1919 ! CHECK: 0xca,0xc4,0x91,0x00
20 addc.f %r17, %r18, %r21
20 addc.f.t %r17, %r18, %r21
2121 ! CHECK: 0xca,0xc6,0x91,0x00
2222 addc %r17, 0, %r21
2323 ! CHECK: 0x1a,0xc4,0x00,0x00
3939 ! CHECK: 0x4a,0xc6,0x12,0x34
4040 and.f %r17, 0x1234ffff, %r21
4141 ! CHECK: 0x4a,0xc7,0x12,0x34
42 and %r17, %r18, %r21
42 and.t %r17, %r18, %r21
4343 ! CHECK: 0xca,0xc4,0x94,0x00
44 and.f %r17, %r18, %r21
44 and.f.t %r17, %r18, %r21
4545 ! CHECK: 0xca,0xc6,0x94,0x00
4646 bt 0x123454
4747 ! CHECK: 0xe0,0x12,0x34,0x54
417417 ! CHECK: 0x5a,0xc6,0x12,0x34
418418 or.f %r17, 0x12340000, %r21
419419 ! CHECK: 0x5a,0xc7,0x12,0x34
420 or %r17, %r18, %r21
420 or.t %r17, %r18, %r21
421421 ! CHECK: 0xca,0xc4,0x95,0x00
422 or.f %r17, %r18, %r21
422 or.f.t %r17, %r18, %r21
423423 ! CHECK: 0xca,0xc6,0x95,0x00
424424 popc %r17, %r21
425425 ! CHECK: 0xda,0xc4,0x00,0x01
789789 ! CHECK: 0x2a,0xc6,0x12,0x34
790790 sub.f %r17, 0x12340000, %r21
791791 ! CHECK: 0x2a,0xc7,0x12,0x34
792 sub %r17, %r18, %r21
792 sub.t %r17, %r18, %r21
793793 ! CHECK: 0xca,0xc4,0x92,0x00
794 sub.f %r17, %r18, %r21
794 sub.f.t %r17, %r18, %r21
795795 ! CHECK: 0xca,0xc6,0x92,0x00
796796 subb %r17, 0, %r21
797797 ! CHECK: 0x3a,0xc4,0x00,0x00
805805 ! CHECK: 0x3a,0xc6,0x12,0x34
806806 subb.f %r17, 0x12340000, %r21
807807 ! CHECK: 0x3a,0xc7,0x12,0x34
808 subb %r17, %r18, %r21
808 subb.t %r17, %r18, %r21
809809 ! CHECK: 0xca,0xc4,0x93,0x00
810 subb.f %r17, %r18, %r21
810 subb.f.t %r17, %r18, %r21
811811 ! CHECK: 0xca,0xc6,0x93,0x00
812812 xor %r17, 0, %r21
813813 ! CHECK: 0x6a,0xc4,0x00,0x00
821821 ! CHECK: 0x6a,0xc6,0x12,0x34
822822 xor.f %r17, 0x12340000, %r21
823823 ! CHECK: 0x6a,0xc7,0x12,0x34
824 xor %r17, %r18, %r21
824 xor.t %r17, %r18, %r21
825825 ! CHECK: 0xca,0xc4,0x96,0x00
826 xor.f %r17, %r18, %r21
826 xor.f.t %r17, %r18, %r21
827827 ! CHECK: 0xca,0xc6,0x96,0x00
828
829
828 sel.ne %r9, %r15, %r12
829 ! CHECK: 0xc6,0x24,0x7f,0x03
830 sel.gt %r9, %r15, %r12
831 ! CHECK: 0xc6,0x24,0x7f,0x07
832 xor.lt %r17, %r18, %r21
833 ! CHECK: 0xca,0xc5,0x96,0x06
834 xor.f.eq %r17, %r18, %r21
835 ! CHECK: 0xca,0xc7,0x96,0x03
836 add.ge %r13, %r14, %r18
837 ! CHECK: 0xc9,0x34,0x70,0x06
838 spl %r19
839 ! CHECK: 0xea,0x4c,0x00,0x02
840 bt 0x1234
841 ! CHECK: 0xe0,0x00,0x12,0x34