Skip to content

Commit b73e10e

Browse files
pftbestTimNN
authored andcommitted
[MSP430] Add SRet support to MSP430 target
This patch adds support for struct return values to the MSP430 target backend. It also reverses the order of argument and return registers in the calling convention to bring it into closer alignment with the published EABI from TI. Patch by Andrew Wygle (awygle). Differential Revision: https://reviews.llvm.org/D29069 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@296807 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 670dac9 commit b73e10e

26 files changed

+277
-172
lines changed

lib/Target/MSP430/MSP430CallingConv.td

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
// MSP430 Return Value Calling Convention
1414
//===----------------------------------------------------------------------===//
1515
def RetCC_MSP430 : CallingConv<[
16-
// i8 are returned in registers R15B, R14B, R13B, R12B
17-
CCIfType<[i8], CCAssignToReg<[R15B, R14B, R13B, R12B]>>,
16+
// i8 are returned in registers R12B, R13B, R14B, R15B
17+
CCIfType<[i8], CCAssignToReg<[R12B, R13B, R14B, R15B]>>,
1818

19-
// i16 are returned in registers R15, R14, R13, R12
20-
CCIfType<[i16], CCAssignToReg<[R15, R14, R13, R12]>>
19+
// i16 are returned in registers R12, R13, R14, R15
20+
CCIfType<[i16], CCAssignToReg<[R12, R13, R14, R15]>>
2121
]>;
2222

2323
//===----------------------------------------------------------------------===//

lib/Target/MSP430/MSP430ISelLowering.cpp

+66-19
Original file line numberDiff line numberDiff line change
@@ -245,13 +245,20 @@ MSP430TargetLowering::getRegForInlineAsmConstraint(
245245
template<typename ArgT>
246246
static void ParseFunctionArgs(const SmallVectorImpl<ArgT> &Args,
247247
SmallVectorImpl<unsigned> &Out) {
248-
unsigned CurrentArgIndex = ~0U;
249-
for (unsigned i = 0, e = Args.size(); i != e; i++) {
250-
if (CurrentArgIndex == Args[i].OrigArgIndex) {
251-
Out.back()++;
248+
unsigned CurrentArgIndex;
249+
250+
if (Args.empty())
251+
return;
252+
253+
CurrentArgIndex = Args[0].OrigArgIndex;
254+
Out.push_back(0);
255+
256+
for (auto &Arg : Args) {
257+
if (CurrentArgIndex == Arg.OrigArgIndex) {
258+
Out.back() += 1;
252259
} else {
253260
Out.push_back(1);
254-
CurrentArgIndex++;
261+
CurrentArgIndex = Arg.OrigArgIndex;
255262
}
256263
}
257264
}
@@ -275,7 +282,7 @@ static void AnalyzeArguments(CCState &State,
275282
SmallVectorImpl<CCValAssign> &ArgLocs,
276283
const SmallVectorImpl<ArgT> &Args) {
277284
static const MCPhysReg RegList[] = {
278-
MSP430::R15, MSP430::R14, MSP430::R13, MSP430::R12
285+
MSP430::R12, MSP430::R13, MSP430::R14, MSP430::R15
279286
};
280287
static const unsigned NbRegs = array_lengthof(RegList);
281288

@@ -288,7 +295,7 @@ static void AnalyzeArguments(CCState &State,
288295
ParseFunctionArgs(Args, ArgsParts);
289296

290297
unsigned RegsLeft = NbRegs;
291-
bool UseStack = false;
298+
bool UsedStack = false;
292299
unsigned ValNo = 0;
293300

294301
for (unsigned i = 0, e = ArgsParts.size(); i != e; i++) {
@@ -316,20 +323,22 @@ static void AnalyzeArguments(CCState &State,
316323

317324
unsigned Parts = ArgsParts[i];
318325

319-
if (!UseStack && Parts <= RegsLeft) {
320-
unsigned FirstVal = ValNo;
326+
if (!UsedStack && Parts == 2 && RegsLeft == 1) {
327+
// Special case for 32-bit register split, see EABI section 3.3.3
328+
unsigned Reg = State.AllocateReg(RegList);
329+
State.addLoc(CCValAssign::getReg(ValNo++, ArgVT, Reg, LocVT, LocInfo));
330+
RegsLeft -= 1;
331+
332+
UsedStack = true;
333+
CC_MSP430_AssignStack(ValNo++, ArgVT, LocVT, LocInfo, ArgFlags, State);
334+
} else if (Parts <= RegsLeft) {
321335
for (unsigned j = 0; j < Parts; j++) {
322336
unsigned Reg = State.AllocateReg(RegList);
323337
State.addLoc(CCValAssign::getReg(ValNo++, ArgVT, Reg, LocVT, LocInfo));
324338
RegsLeft--;
325339
}
326-
327-
// Reverse the order of the pieces to agree with the "big endian" format
328-
// required in the calling convention ABI.
329-
SmallVectorImpl<CCValAssign>::iterator B = ArgLocs.begin() + FirstVal;
330-
std::reverse(B, B + Parts);
331340
} else {
332-
UseStack = true;
341+
UsedStack = true;
333342
for (unsigned j = 0; j < Parts; j++)
334343
CC_MSP430_AssignStack(ValNo++, ArgVT, LocVT, LocInfo, ArgFlags, State);
335344
}
@@ -351,10 +360,6 @@ static void AnalyzeReturnValues(CCState &State,
351360
SmallVectorImpl<CCValAssign> &RVLocs,
352361
const SmallVectorImpl<ArgT> &Args) {
353362
AnalyzeRetResult(State, Args);
354-
355-
// Reverse splitted return values to get the "big endian" format required
356-
// to agree with the calling convention ABI.
357-
std::reverse(RVLocs.begin(), RVLocs.end());
358363
}
359364

360365
SDValue MSP430TargetLowering::LowerFormalArguments(
@@ -496,16 +501,42 @@ SDValue MSP430TargetLowering::LowerCCCArguments(
496501
}
497502
}
498503

504+
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
505+
if (Ins[i].Flags.isSRet()) {
506+
unsigned Reg = FuncInfo->getSRetReturnReg();
507+
if (!Reg) {
508+
Reg = MF.getRegInfo().createVirtualRegister(
509+
getRegClassFor(MVT::i16));
510+
FuncInfo->setSRetReturnReg(Reg);
511+
}
512+
SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), dl, Reg, InVals[i]);
513+
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Chain);
514+
}
515+
}
516+
499517
return Chain;
500518
}
501519

520+
bool
521+
MSP430TargetLowering::CanLowerReturn(CallingConv::ID CallConv,
522+
MachineFunction &MF,
523+
bool IsVarArg,
524+
const SmallVectorImpl<ISD::OutputArg> &Outs,
525+
LLVMContext &Context) const {
526+
SmallVector<CCValAssign, 16> RVLocs;
527+
CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
528+
return CCInfo.CheckReturn(Outs, RetCC_MSP430);
529+
}
530+
502531
SDValue
503532
MSP430TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
504533
bool isVarArg,
505534
const SmallVectorImpl<ISD::OutputArg> &Outs,
506535
const SmallVectorImpl<SDValue> &OutVals,
507536
const SDLoc &dl, SelectionDAG &DAG) const {
508537

538+
MachineFunction &MF = DAG.getMachineFunction();
539+
509540
// CCValAssign - represent the assignment of the return value to a location
510541
SmallVector<CCValAssign, 16> RVLocs;
511542

@@ -537,6 +568,22 @@ MSP430TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
537568
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
538569
}
539570

571+
if (MF.getFunction()->hasStructRetAttr()) {
572+
MSP430MachineFunctionInfo *FuncInfo = MF.getInfo<MSP430MachineFunctionInfo>();
573+
unsigned Reg = FuncInfo->getSRetReturnReg();
574+
575+
if (!Reg)
576+
llvm_unreachable("sret virtual register not created in entry block");
577+
578+
SDValue Val =
579+
DAG.getCopyFromReg(Chain, dl, Reg, getPointerTy(DAG.getDataLayout()));
580+
unsigned R12 = MSP430::R12;
581+
582+
Chain = DAG.getCopyToReg(Chain, dl, R12, Val, Flag);
583+
Flag = Chain.getValue(1);
584+
RetOps.push_back(DAG.getRegister(R12, getPointerTy(DAG.getDataLayout())));
585+
}
586+
540587
unsigned Opc = (CallConv == CallingConv::MSP430_INTR ?
541588
MSP430ISD::RETI_FLAG : MSP430ISD::RET_FLAG);
542589

lib/Target/MSP430/MSP430ISelLowering.h

+6
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ namespace llvm {
158158
LowerCall(TargetLowering::CallLoweringInfo &CLI,
159159
SmallVectorImpl<SDValue> &InVals) const override;
160160

161+
bool CanLowerReturn(CallingConv::ID CallConv,
162+
MachineFunction &MF,
163+
bool IsVarArg,
164+
const SmallVectorImpl<ISD::OutputArg> &Outs,
165+
LLVMContext &Context) const override;
166+
161167
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
162168
const SmallVectorImpl<ISD::OutputArg> &Outs,
163169
const SmallVectorImpl<SDValue> &OutVals,

lib/Target/MSP430/MSP430MachineFunctionInfo.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,23 @@ class MSP430MachineFunctionInfo : public MachineFunctionInfo {
3333
/// VarArgsFrameIndex - FrameIndex for start of varargs area.
3434
int VarArgsFrameIndex;
3535

36+
/// SRetReturnReg - Some subtargets require that sret lowering includes
37+
/// returning the value of the returned struct in a register. This field
38+
/// holds the virtual register into which the sret argument is passed.
39+
unsigned SRetReturnReg;
40+
3641
public:
3742
MSP430MachineFunctionInfo() : CalleeSavedFrameSize(0) {}
3843

3944
explicit MSP430MachineFunctionInfo(MachineFunction &MF)
40-
: CalleeSavedFrameSize(0), ReturnAddrIndex(0) {}
45+
: CalleeSavedFrameSize(0), ReturnAddrIndex(0), SRetReturnReg(0) {}
4146

4247
unsigned getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; }
4348
void setCalleeSavedFrameSize(unsigned bytes) { CalleeSavedFrameSize = bytes; }
4449

50+
unsigned getSRetReturnReg() const { return SRetReturnReg; }
51+
void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; }
52+
4553
int getRAIndex() const { return ReturnAddrIndex; }
4654
void setRAIndex(int Index) { ReturnAddrIndex = Index; }
4755

test/CodeGen/MSP430/AddrMode-bis-rx.ll

+7-7
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ define i16 @am1(i16 %x, i16* %a) nounwind {
88
ret i16 %2
99
}
1010
; CHECK-LABEL: am1:
11-
; CHECK: bis.w 0(r14), r15
11+
; CHECK: bis.w 0(r13), r12
1212

1313
@foo = external global i16
1414

@@ -18,7 +18,7 @@ define i16 @am2(i16 %x) nounwind {
1818
ret i16 %2
1919
}
2020
; CHECK-LABEL: am2:
21-
; CHECK: bis.w &foo, r15
21+
; CHECK: bis.w &foo, r12
2222

2323
@bar = internal constant [2 x i8] [ i8 32, i8 64 ]
2424

@@ -29,15 +29,15 @@ define i8 @am3(i8 %x, i16 %n) nounwind {
2929
ret i8 %3
3030
}
3131
; CHECK-LABEL: am3:
32-
; CHECK: bis.b bar(r14), r15
32+
; CHECK: bis.b bar(r13), r12
3333

3434
define i16 @am4(i16 %x) nounwind {
3535
%1 = load volatile i16, i16* inttoptr(i16 32 to i16*)
3636
%2 = or i16 %1,%x
3737
ret i16 %2
3838
}
3939
; CHECK-LABEL: am4:
40-
; CHECK: bis.w &32, r15
40+
; CHECK: bis.w &32, r12
4141

4242
define i16 @am5(i16 %x, i16* %a) nounwind {
4343
%1 = getelementptr i16, i16* %a, i16 2
@@ -46,7 +46,7 @@ define i16 @am5(i16 %x, i16* %a) nounwind {
4646
ret i16 %3
4747
}
4848
; CHECK-LABEL: am5:
49-
; CHECK: bis.w 4(r14), r15
49+
; CHECK: bis.w 4(r13), r12
5050

5151
%S = type { i16, i16 }
5252
@baz = common global %S zeroinitializer, align 1
@@ -57,7 +57,7 @@ define i16 @am6(i16 %x) nounwind {
5757
ret i16 %2
5858
}
5959
; CHECK-LABEL: am6:
60-
; CHECK: bis.w &baz+2, r15
60+
; CHECK: bis.w &baz+2, r12
6161

6262
%T = type { i16, [2 x i8] }
6363
@duh = internal constant %T { i16 16, [2 x i8][i8 32, i8 64 ] }
@@ -70,5 +70,5 @@ define i8 @am7(i8 %x, i16 %n) nounwind {
7070
ret i8 %4
7171
}
7272
; CHECK-LABEL: am7:
73-
; CHECK: bis.b duh+2(r14), r15
73+
; CHECK: bis.b duh+2(r13), r12
7474

test/CodeGen/MSP430/AddrMode-bis-xr.ll

+7-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ define void @am1(i16* %a, i16 %x) nounwind {
99
ret void
1010
}
1111
; CHECK-LABEL: am1:
12-
; CHECK: bis.w r14, 0(r15)
12+
; CHECK: bis.w r13, 0(r12)
1313

1414
@foo = external global i16
1515

@@ -20,7 +20,7 @@ define void @am2(i16 %x) nounwind {
2020
ret void
2121
}
2222
; CHECK-LABEL: am2:
23-
; CHECK: bis.w r15, &foo
23+
; CHECK: bis.w r12, &foo
2424

2525
@bar = external global [2 x i8]
2626

@@ -32,7 +32,7 @@ define void @am3(i16 %i, i8 %x) nounwind {
3232
ret void
3333
}
3434
; CHECK-LABEL: am3:
35-
; CHECK: bis.b r14, bar(r15)
35+
; CHECK: bis.b r13, bar(r12)
3636

3737
define void @am4(i16 %x) nounwind {
3838
%1 = load volatile i16, i16* inttoptr(i16 32 to i16*)
@@ -41,7 +41,7 @@ define void @am4(i16 %x) nounwind {
4141
ret void
4242
}
4343
; CHECK-LABEL: am4:
44-
; CHECK: bis.w r15, &32
44+
; CHECK: bis.w r12, &32
4545

4646
define void @am5(i16* %a, i16 %x) readonly {
4747
%1 = getelementptr inbounds i16, i16* %a, i16 2
@@ -51,7 +51,7 @@ define void @am5(i16* %a, i16 %x) readonly {
5151
ret void
5252
}
5353
; CHECK-LABEL: am5:
54-
; CHECK: bis.w r14, 4(r15)
54+
; CHECK: bis.w r13, 4(r12)
5555

5656
%S = type { i16, i16 }
5757
@baz = common global %S zeroinitializer
@@ -63,7 +63,7 @@ define void @am6(i16 %x) nounwind {
6363
ret void
6464
}
6565
; CHECK-LABEL: am6:
66-
; CHECK: bis.w r15, &baz+2
66+
; CHECK: bis.w r12, &baz+2
6767

6868
%T = type { i16, [2 x i8] }
6969
@duh = external global %T
@@ -77,5 +77,5 @@ define void @am7(i16 %n, i8 %x) nounwind {
7777
ret void
7878
}
7979
; CHECK-LABEL: am7:
80-
; CHECK: bis.b r14, duh+2(r15)
80+
; CHECK: bis.b r13, duh+2(r12)
8181

test/CodeGen/MSP430/AddrMode-mov-rx.ll

+7-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ define i16 @am1(i16* %a) nounwind {
77
ret i16 %1
88
}
99
; CHECK-LABEL: am1:
10-
; CHECK: mov.w 0(r15), r15
10+
; CHECK: mov.w 0(r12), r12
1111

1212
@foo = external global i16
1313

@@ -16,7 +16,7 @@ define i16 @am2() nounwind {
1616
ret i16 %1
1717
}
1818
; CHECK-LABEL: am2:
19-
; CHECK: mov.w &foo, r15
19+
; CHECK: mov.w &foo, r12
2020

2121
@bar = internal constant [2 x i8] [ i8 32, i8 64 ]
2222

@@ -26,22 +26,22 @@ define i8 @am3(i16 %n) nounwind {
2626
ret i8 %2
2727
}
2828
; CHECK-LABEL: am3:
29-
; CHECK: mov.b bar(r15), r15
29+
; CHECK: mov.b bar(r12), r12
3030

3131
define i16 @am4() nounwind {
3232
%1 = load volatile i16, i16* inttoptr(i16 32 to i16*)
3333
ret i16 %1
3434
}
3535
; CHECK-LABEL: am4:
36-
; CHECK: mov.w &32, r15
36+
; CHECK: mov.w &32, r12
3737

3838
define i16 @am5(i16* %a) nounwind {
3939
%1 = getelementptr i16, i16* %a, i16 2
4040
%2 = load i16, i16* %1
4141
ret i16 %2
4242
}
4343
; CHECK-LABEL: am5:
44-
; CHECK: mov.w 4(r15), r15
44+
; CHECK: mov.w 4(r12), r12
4545

4646
%S = type { i16, i16 }
4747
@baz = common global %S zeroinitializer, align 1
@@ -51,7 +51,7 @@ define i16 @am6() nounwind {
5151
ret i16 %1
5252
}
5353
; CHECK-LABEL: am6:
54-
; CHECK: mov.w &baz+2, r15
54+
; CHECK: mov.w &baz+2, r12
5555

5656
%T = type { i16, [2 x i8] }
5757
@duh = internal constant %T { i16 16, [2 x i8][i8 32, i8 64 ] }
@@ -63,5 +63,5 @@ define i8 @am7(i16 %n) nounwind {
6363
ret i8 %3
6464
}
6565
; CHECK-LABEL: am7:
66-
; CHECK: mov.b duh+2(r15), r15
66+
; CHECK: mov.b duh+2(r12), r12
6767

0 commit comments

Comments
 (0)