Skip to content

Commit f319c24

Browse files
committed
[AVR] Reject/Reserve R0~R15 on AVRTiny.
Reviewed By: aykevl, dylanmckay Differential Revision: https://reviews.llvm.org/D121672
1 parent 8474668 commit f319c24

File tree

6 files changed

+320
-18
lines changed

6 files changed

+320
-18
lines changed

llvm/lib/Target/AVR/AVRCallingConv.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,6 @@ def ArgCC_AVR_Vararg : CallingConv<[
3838
//===----------------------------------------------------------------------===//
3939

4040
def CSR_Normal : CalleeSavedRegs<(add R29, R28, (sequence "R%u", 17, 2))>;
41+
def CSR_NormalTiny : CalleeSavedRegs<(add R29, R28, R19, R18)>;
4142
def CSR_Interrupts : CalleeSavedRegs<(add(sequence "R%u", 31, 2))>;
43+
def CSR_InterruptsTiny : CalleeSavedRegs<(add(sequence "R%u", 31, 18))>;

llvm/lib/Target/AVR/AVRISelLowering.cpp

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "AVRISelLowering.h"
1515

16+
#include "llvm/ADT/ArrayRef.h"
1617
#include "llvm/ADT/STLExtras.h"
1718
#include "llvm/ADT/StringSwitch.h"
1819
#include "llvm/CodeGen/CallingConvLower.h"
@@ -1023,28 +1024,47 @@ bool AVRTargetLowering::isOffsetFoldingLegal(
10231024

10241025
/// Registers for calling conventions, ordered in reverse as required by ABI.
10251026
/// Both arrays must be of the same length.
1026-
static const MCPhysReg RegList8[] = {
1027+
static const MCPhysReg RegList8AVR[] = {
10271028
AVR::R25, AVR::R24, AVR::R23, AVR::R22, AVR::R21, AVR::R20,
10281029
AVR::R19, AVR::R18, AVR::R17, AVR::R16, AVR::R15, AVR::R14,
10291030
AVR::R13, AVR::R12, AVR::R11, AVR::R10, AVR::R9, AVR::R8};
1030-
static const MCPhysReg RegList16[] = {
1031+
static const MCPhysReg RegList8Tiny[] = {AVR::R25, AVR::R24, AVR::R23,
1032+
AVR::R22, AVR::R21, AVR::R20};
1033+
static const MCPhysReg RegList16AVR[] = {
10311034
AVR::R26R25, AVR::R25R24, AVR::R24R23, AVR::R23R22, AVR::R22R21,
10321035
AVR::R21R20, AVR::R20R19, AVR::R19R18, AVR::R18R17, AVR::R17R16,
10331036
AVR::R16R15, AVR::R15R14, AVR::R14R13, AVR::R13R12, AVR::R12R11,
10341037
AVR::R11R10, AVR::R10R9, AVR::R9R8};
1038+
static const MCPhysReg RegList16Tiny[] = {AVR::R26R25, AVR::R25R24,
1039+
AVR::R24R23, AVR::R23R22,
1040+
AVR::R22R21, AVR::R21R20};
10351041

1036-
static_assert(array_lengthof(RegList8) == array_lengthof(RegList16),
1042+
static_assert(array_lengthof(RegList8AVR) == array_lengthof(RegList16AVR),
1043+
"8-bit and 16-bit register arrays must be of equal length");
1044+
static_assert(array_lengthof(RegList8Tiny) == array_lengthof(RegList16Tiny),
10371045
"8-bit and 16-bit register arrays must be of equal length");
10381046

10391047
/// Analyze incoming and outgoing function arguments. We need custom C++ code
10401048
/// to handle special constraints in the ABI.
10411049
/// In addition, all pieces of a certain argument have to be passed either
10421050
/// using registers or the stack but never mixing both.
10431051
template <typename ArgT>
1044-
static void
1045-
analyzeArguments(TargetLowering::CallLoweringInfo *CLI, const Function *F,
1046-
const DataLayout *TD, const SmallVectorImpl<ArgT> &Args,
1047-
SmallVectorImpl<CCValAssign> &ArgLocs, CCState &CCInfo) {
1052+
static void analyzeArguments(TargetLowering::CallLoweringInfo *CLI,
1053+
const Function *F, const DataLayout *TD,
1054+
const SmallVectorImpl<ArgT> &Args,
1055+
SmallVectorImpl<CCValAssign> &ArgLocs,
1056+
CCState &CCInfo, bool Tiny) {
1057+
// Choose the proper register list for argument passing according to the ABI.
1058+
ArrayRef<MCPhysReg> RegList8;
1059+
ArrayRef<MCPhysReg> RegList16;
1060+
if (Tiny) {
1061+
RegList8 = makeArrayRef(RegList8Tiny, array_lengthof(RegList8Tiny));
1062+
RegList16 = makeArrayRef(RegList16Tiny, array_lengthof(RegList16Tiny));
1063+
} else {
1064+
RegList8 = makeArrayRef(RegList8AVR, array_lengthof(RegList8AVR));
1065+
RegList16 = makeArrayRef(RegList16AVR, array_lengthof(RegList16AVR));
1066+
}
1067+
10481068
unsigned NumArgs = Args.size();
10491069
// This is the index of the last used register, in RegList*.
10501070
// -1 means R26 (R26 is never actually used in CC).
@@ -1074,7 +1094,7 @@ analyzeArguments(TargetLowering::CallLoweringInfo *CLI, const Function *F,
10741094
unsigned RegIdx = RegLastIdx + TotalBytes;
10751095
RegLastIdx = RegIdx;
10761096
// If there are not enough registers, use the stack
1077-
if (RegIdx >= array_lengthof(RegList8)) {
1097+
if (RegIdx >= RegList8.size()) {
10781098
UseStack = true;
10791099
}
10801100
for (; i != j; ++i) {
@@ -1123,13 +1143,24 @@ getTotalArgumentsSizeInBytes(const SmallVectorImpl<ArgT> &Args) {
11231143
/// one value, possibly an aggregate, and it is limited to 8 bytes.
11241144
template <typename ArgT>
11251145
static void analyzeReturnValues(const SmallVectorImpl<ArgT> &Args,
1126-
CCState &CCInfo) {
1146+
CCState &CCInfo, bool Tiny) {
11271147
unsigned NumArgs = Args.size();
11281148
unsigned TotalBytes = getTotalArgumentsSizeInBytes(Args);
11291149
// CanLowerReturn() guarantees this assertion.
11301150
assert(TotalBytes <= 8 &&
11311151
"return values greater than 8 bytes cannot be lowered");
11321152

1153+
// Choose the proper register list for argument passing according to the ABI.
1154+
ArrayRef<MCPhysReg> RegList8;
1155+
ArrayRef<MCPhysReg> RegList16;
1156+
if (Tiny) {
1157+
RegList8 = makeArrayRef(RegList8Tiny, array_lengthof(RegList8Tiny));
1158+
RegList16 = makeArrayRef(RegList16Tiny, array_lengthof(RegList16Tiny));
1159+
} else {
1160+
RegList8 = makeArrayRef(RegList8AVR, array_lengthof(RegList8AVR));
1161+
RegList16 = makeArrayRef(RegList16AVR, array_lengthof(RegList16AVR));
1162+
}
1163+
11331164
// GCC-ABI says that the size is rounded up to the next even number,
11341165
// but actually once it is more than 4 it will always round up to 8.
11351166
if (TotalBytes > 4) {
@@ -1174,7 +1205,8 @@ SDValue AVRTargetLowering::LowerFormalArguments(
11741205
if (isVarArg) {
11751206
CCInfo.AnalyzeFormalArguments(Ins, ArgCC_AVR_Vararg);
11761207
} else {
1177-
analyzeArguments(nullptr, &MF.getFunction(), &DL, Ins, ArgLocs, CCInfo);
1208+
analyzeArguments(nullptr, &MF.getFunction(), &DL, Ins, ArgLocs, CCInfo,
1209+
Subtarget.hasTinyEncoding());
11781210
}
11791211

11801212
SDValue ArgValue;
@@ -1299,7 +1331,8 @@ SDValue AVRTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
12991331
if (isVarArg) {
13001332
CCInfo.AnalyzeCallOperands(Outs, ArgCC_AVR_Vararg);
13011333
} else {
1302-
analyzeArguments(&CLI, F, &DAG.getDataLayout(), Outs, ArgLocs, CCInfo);
1334+
analyzeArguments(&CLI, F, &DAG.getDataLayout(), Outs, ArgLocs, CCInfo,
1335+
Subtarget.hasTinyEncoding());
13031336
}
13041337

13051338
// Get a count of how many bytes are to be pushed on the stack.
@@ -1444,7 +1477,7 @@ SDValue AVRTargetLowering::LowerCallResult(
14441477
if (CallConv == CallingConv::AVR_BUILTIN) {
14451478
CCInfo.AnalyzeCallResult(Ins, RetCC_AVR_BUILTIN);
14461479
} else {
1447-
analyzeReturnValues(Ins, CCInfo);
1480+
analyzeReturnValues(Ins, CCInfo, Subtarget.hasTinyEncoding());
14481481
}
14491482

14501483
// Copy all of the result registers out of their specified physreg.
@@ -1495,7 +1528,7 @@ AVRTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
14951528
if (CallConv == CallingConv::AVR_BUILTIN) {
14961529
CCInfo.AnalyzeReturn(Outs, RetCC_AVR_BUILTIN);
14971530
} else {
1498-
analyzeReturnValues(Outs, CCInfo);
1531+
analyzeReturnValues(Outs, CCInfo, Subtarget.hasTinyEncoding());
14991532
}
15001533

15011534
SDValue Flag;

llvm/lib/Target/AVR/AVRRegisterInfo.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,31 +36,47 @@ AVRRegisterInfo::AVRRegisterInfo() : AVRGenRegisterInfo(0) {}
3636
const uint16_t *
3737
AVRRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
3838
const AVRMachineFunctionInfo *AFI = MF->getInfo<AVRMachineFunctionInfo>();
39-
40-
return AFI->isInterruptOrSignalHandler() ? CSR_Interrupts_SaveList
41-
: CSR_Normal_SaveList;
39+
const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
40+
if (STI.hasTinyEncoding())
41+
return AFI->isInterruptOrSignalHandler() ? CSR_InterruptsTiny_SaveList
42+
: CSR_NormalTiny_SaveList;
43+
else
44+
return AFI->isInterruptOrSignalHandler() ? CSR_Interrupts_SaveList
45+
: CSR_Normal_SaveList;
4246
}
4347

4448
const uint32_t *
4549
AVRRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
4650
CallingConv::ID CC) const {
47-
return CSR_Normal_RegMask;
51+
const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
52+
return STI.hasTinyEncoding() ? CSR_NormalTiny_RegMask : CSR_Normal_RegMask;
4853
}
4954

5055
BitVector AVRRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
5156
BitVector Reserved(getNumRegs());
5257

5358
// Reserve the intermediate result registers r1 and r2
5459
// The result of instructions like 'mul' is always stored here.
60+
// R0/R1/R1R0 are always reserved on both avr and avrtiny.
5561
Reserved.set(AVR::R0);
5662
Reserved.set(AVR::R1);
5763
Reserved.set(AVR::R1R0);
5864

59-
// Reserve the stack pointer.
65+
// Reserve the stack pointer.
6066
Reserved.set(AVR::SPL);
6167
Reserved.set(AVR::SPH);
6268
Reserved.set(AVR::SP);
6369

70+
// Reserve R2~R17 only on avrtiny.
71+
if (MF.getSubtarget<AVRSubtarget>().hasTinyEncoding()) {
72+
// Reserve 8-bit registers R2~R15, Rtmp(R16) and Zero(R17).
73+
for (unsigned Reg = AVR::R2; Reg <= AVR::R17; Reg++)
74+
Reserved.set(Reg);
75+
// Reserve 16-bit registers R3R2~R18R17.
76+
for (unsigned Reg = AVR::R3R2; Reg <= AVR::R18R17; Reg++)
77+
Reserved.set(Reg);
78+
}
79+
6480
// We tenatively reserve the frame pointer register r29:r28 because the
6581
// function may require one, but we cannot tell until register allocation
6682
// is complete, which can be too late.

llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ class AVRAsmParser : public MCTargetAsmParser {
4343
const MCRegisterInfo *MRI;
4444
const std::string GENERATE_STUBS = "gs";
4545

46+
enum AVRMatchResultTy {
47+
Match_InvalidRegisterOnTiny = FIRST_TARGET_MATCH_RESULT_TY + 1,
48+
};
49+
4650
#define GET_ASSEMBLER_HEADER
4751
#include "AVRGenAsmMatcher.inc"
4852

@@ -332,6 +336,8 @@ bool AVRAsmParser::MatchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,
332336
return invalidOperand(Loc, Operands, ErrorInfo);
333337
case Match_MnemonicFail:
334338
return Error(Loc, "invalid instruction");
339+
case Match_InvalidRegisterOnTiny:
340+
return Error(Loc, "invalid register on avrtiny");
335341
default:
336342
return true;
337343
}
@@ -399,6 +405,11 @@ bool AVRAsmParser::tryParseRegisterOperand(OperandVector &Operands) {
399405
if (RegNo == AVR::NoRegister)
400406
return true;
401407

408+
// Reject R0~R15 on avrtiny.
409+
if (AVR::R0 <= RegNo && RegNo <= AVR::R15 &&
410+
STI.hasFeature(AVR::FeatureTinyEncoding))
411+
return Error(Parser.getTok().getLoc(), "invalid register on avrtiny");
412+
402413
AsmToken const &T = Parser.getTok();
403414
Operands.push_back(AVROperand::CreateReg(RegNo, T.getLoc(), T.getEndLoc()));
404415
Parser.Lex(); // Eat register token.
@@ -726,6 +737,12 @@ unsigned AVRAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
726737
if (Op.isImm()) {
727738
if (MCConstantExpr const *Const = dyn_cast<MCConstantExpr>(Op.getImm())) {
728739
int64_t RegNum = Const->getValue();
740+
741+
// Reject R0~R15 on avrtiny.
742+
if (0 <= RegNum && RegNum <= 15 &&
743+
STI.hasFeature(AVR::FeatureTinyEncoding))
744+
return Match_InvalidRegisterOnTiny;
745+
729746
std::ostringstream RegName;
730747
RegName << "r" << RegNum;
731748
RegNum = MatchRegisterName(RegName.str());

0 commit comments

Comments
 (0)