Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit 9c467a8

Browse files
committed
[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 50ab09f commit 9c467a8

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
@@ -246,13 +246,20 @@ MSP430TargetLowering::getRegForInlineAsmConstraint(
246246
template<typename ArgT>
247247
static void ParseFunctionArgs(const SmallVectorImpl<ArgT> &Args,
248248
SmallVectorImpl<unsigned> &Out) {
249-
unsigned CurrentArgIndex = ~0U;
250-
for (unsigned i = 0, e = Args.size(); i != e; i++) {
251-
if (CurrentArgIndex == Args[i].OrigArgIndex) {
252-
Out.back()++;
249+
unsigned CurrentArgIndex;
250+
251+
if (Args.empty())
252+
return;
253+
254+
CurrentArgIndex = Args[0].OrigArgIndex;
255+
Out.push_back(0);
256+
257+
for (auto &Arg : Args) {
258+
if (CurrentArgIndex == Arg.OrigArgIndex) {
259+
Out.back() += 1;
253260
} else {
254261
Out.push_back(1);
255-
CurrentArgIndex++;
262+
CurrentArgIndex = Arg.OrigArgIndex;
256263
}
257264
}
258265
}
@@ -276,7 +283,7 @@ static void AnalyzeArguments(CCState &State,
276283
SmallVectorImpl<CCValAssign> &ArgLocs,
277284
const SmallVectorImpl<ArgT> &Args) {
278285
static const MCPhysReg RegList[] = {
279-
MSP430::R15, MSP430::R14, MSP430::R13, MSP430::R12
286+
MSP430::R12, MSP430::R13, MSP430::R14, MSP430::R15
280287
};
281288
static const unsigned NbRegs = array_lengthof(RegList);
282289

@@ -289,7 +296,7 @@ static void AnalyzeArguments(CCState &State,
289296
ParseFunctionArgs(Args, ArgsParts);
290297

291298
unsigned RegsLeft = NbRegs;
292-
bool UseStack = false;
299+
bool UsedStack = false;
293300
unsigned ValNo = 0;
294301

295302
for (unsigned i = 0, e = ArgsParts.size(); i != e; i++) {
@@ -317,20 +324,22 @@ static void AnalyzeArguments(CCState &State,
317324

318325
unsigned Parts = ArgsParts[i];
319326

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

361366
SDValue MSP430TargetLowering::LowerFormalArguments(
@@ -497,16 +502,42 @@ SDValue MSP430TargetLowering::LowerCCCArguments(
497502
}
498503
}
499504

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

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

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

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

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

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)