llvm.org GIT mirror llvm / 456ca04
Add CodeGen support for functions that always return arguments via a new parameter attribute 'returned', which is taken advantage of in target-independent tail call opportunity detection and in ARM call lowering (when placed on an integral first parameter). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@179925 91177308-0d34-0410-b5e6-96231b3b80d8 Stephen Lin 7 years ago
20 changed file(s) with 371 addition(s) and 43 deletion(s). Raw diff Collapse all Expand all
718718 ``nest``
719719 This indicates that the pointer parameter can be excised using the
720720 :ref:`trampoline intrinsics `. This is not a valid
721 attribute for return values.
721 attribute for return values and can only be applied to one parameter.
722
723 ``returned``
724 This indicates that the value of the function always returns the value
725 of the parameter as its return value. This is an optimization hint to
726 the code generator when generating the caller, allowing tail call
727 optimization and omission of register saves and restores in some cases;
728 it is not checked or enforced when generating the callee. The parameter
729 and the function return type must be valid operands for the
730 :ref:`bitcast instruction `. This is not a valid attribute for
731 return values and can only be applied to one parameter.
722732
723733 .. _gc:
724734
7777 /// containing function.
7878 bool hasStructRetAttr() const;
7979
80 /// \brief Return true if this argument has the returned attribute on it in
81 /// its containing function.
82 bool hasReturnedAttr() const;
83
8084 /// \brief Add a Attribute to an argument.
8185 void addAttr(AttributeSet AS);
8286
8686 OptimizeForSize, ///< opt_size
8787 ReadNone, ///< Function does not access memory
8888 ReadOnly, ///< Function only reads from memory
89 Returned, ///< Return value is always equal to this argument
8990 ReturnsTwice, ///< Function can return twice
9091 SExt, ///< Sign extended before/after call
9192 StackAlignment, ///< Alignment of stack for function (3 bits)
3535 static const uint64_t ByValOffs = 4;
3636 static const uint64_t Nest = 1ULL<<5; ///< Nested fn static chain
3737 static const uint64_t NestOffs = 5;
38 static const uint64_t ByValAlign = 0xFULL << 6; ///< Struct alignment
39 static const uint64_t ByValAlignOffs = 6;
40 static const uint64_t Split = 1ULL << 10;
41 static const uint64_t SplitOffs = 10;
38 static const uint64_t Returned = 1ULL<<6;
39 static const uint64_t ReturnedOffs = 6;
40 static const uint64_t ByValAlign = 0xFULL<<7; ///< Struct alignment
41 static const uint64_t ByValAlignOffs = 7;
42 static const uint64_t Split = 1ULL<<11;
43 static const uint64_t SplitOffs = 11;
4244 static const uint64_t OrigAlign = 0x1FULL<<27;
4345 static const uint64_t OrigAlignOffs = 27;
4446 static const uint64_t ByValSize = 0xffffffffULL << 32; ///< Struct size
5052 public:
5153 ArgFlagsTy() : Flags(0) { }
5254
53 bool isZExt() const { return Flags & ZExt; }
54 void setZExt() { Flags |= One << ZExtOffs; }
55 bool isZExt() const { return Flags & ZExt; }
56 void setZExt() { Flags |= One << ZExtOffs; }
5557
56 bool isSExt() const { return Flags & SExt; }
57 void setSExt() { Flags |= One << SExtOffs; }
58 bool isSExt() const { return Flags & SExt; }
59 void setSExt() { Flags |= One << SExtOffs; }
5860
59 bool isInReg() const { return Flags & InReg; }
60 void setInReg() { Flags |= One << InRegOffs; }
61 bool isInReg() const { return Flags & InReg; }
62 void setInReg() { Flags |= One << InRegOffs; }
6163
62 bool isSRet() const { return Flags & SRet; }
63 void setSRet() { Flags |= One << SRetOffs; }
64 bool isSRet() const { return Flags & SRet; }
65 void setSRet() { Flags |= One << SRetOffs; }
6466
65 bool isByVal() const { return Flags & ByVal; }
66 void setByVal() { Flags |= One << ByValOffs; }
67 bool isByVal() const { return Flags & ByVal; }
68 void setByVal() { Flags |= One << ByValOffs; }
6769
68 bool isNest() const { return Flags & Nest; }
69 void setNest() { Flags |= One << NestOffs; }
70 bool isNest() const { return Flags & Nest; }
71 void setNest() { Flags |= One << NestOffs; }
72
73 bool isReturned() const { return Flags & Returned; }
74 void setReturned() { Flags |= One << ReturnedOffs; }
7075
7176 unsigned getByValAlign() const {
7277 return (unsigned)
19091909 struct ArgListEntry {
19101910 SDValue Node;
19111911 Type* Ty;
1912 bool isSExt : 1;
1913 bool isZExt : 1;
1914 bool isInReg : 1;
1915 bool isSRet : 1;
1916 bool isNest : 1;
1917 bool isByVal : 1;
1912 bool isSExt : 1;
1913 bool isZExt : 1;
1914 bool isInReg : 1;
1915 bool isSRet : 1;
1916 bool isNest : 1;
1917 bool isByVal : 1;
1918 bool isReturned : 1;
19181919 uint16_t Alignment;
19191920
19201921 ArgListEntry() : isSExt(false), isZExt(false), isInReg(false),
1921 isSRet(false), isNest(false), isByVal(false), Alignment(0) { }
1922 isSRet(false), isNest(false), isByVal(false), isReturned(false),
1923 Alignment(0) { }
19221924 };
19231925 typedef std::vector ArgListTy;
19241926
581581 KEYWORD(optsize);
582582 KEYWORD(readnone);
583583 KEYWORD(readonly);
584 KEYWORD(returned);
584585 KEYWORD(returns_twice);
585586 KEYWORD(signext);
586587 KEYWORD(sret);
943943 case lltok::kw_nest:
944944 case lltok::kw_noalias:
945945 case lltok::kw_nocapture:
946 case lltok::kw_returned:
946947 case lltok::kw_sret:
947948 HaveError |=
948949 Error(Lex.getLoc(),
11551156 case lltok::kw_nest: B.addAttribute(Attribute::Nest); break;
11561157 case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break;
11571158 case lltok::kw_nocapture: B.addAttribute(Attribute::NoCapture); break;
1159 case lltok::kw_returned: B.addAttribute(Attribute::Returned); break;
11581160 case lltok::kw_signext: B.addAttribute(Attribute::SExt); break;
11591161 case lltok::kw_sret: B.addAttribute(Attribute::StructRet); break;
11601162 case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;
11981200 case lltok::kw_byval:
11991201 case lltok::kw_nest:
12001202 case lltok::kw_nocapture:
1203 case lltok::kw_returned:
12011204 case lltok::kw_sret:
12021205 HaveError |= Error(Lex.getLoc(), "invalid use of parameter-only attribute");
12031206 break;
113113 kw_optsize,
114114 kw_readnone,
115115 kw_readonly,
116 kw_returned,
116117 kw_returns_twice,
117118 kw_signext,
118119 kw_ssp,
260260 TLI.getPointerTy().getSizeInBits() ==
261261 cast(I->getType())->getBitWidth())
262262 NoopInput = Op;
263 } else if (isa(I)) {
264 // Look through call
265 for (User::const_op_iterator i = I->op_begin(),
266 // Skip Callee
267 e = I->op_end() - 1;
268 i != e; ++i) {
269 unsigned attrInd = i - I->op_begin() + 1;
270 if (cast(I)->paramHasAttr(attrInd, Attribute::Returned) &&
271 isNoopBitcast((*i)->getType(), I->getType(), TLI)) {
272 NoopInput = *i;
273 break;
274 }
275 }
276 } else if (isa(I)) {
277 // Look through invoke
278 for (User::const_op_iterator i = I->op_begin(),
279 // Skip BB, BB, Callee
280 e = I->op_end() - 3;
281 i != e; ++i) {
282 unsigned attrInd = i - I->op_begin() + 1;
283 if (cast(I)->paramHasAttr(attrInd, Attribute::Returned) &&
284 isNoopBitcast((*i)->getType(), I->getType(), TLI)) {
285 NoopInput = *i;
286 break;
287 }
288 }
263289 }
264290 }
265291
52315231 Entry.isSRet = true;
52325232 Entry.isNest = false;
52335233 Entry.isByVal = false;
5234 Entry.isReturned = false;
52345235 Entry.Alignment = Align;
52355236 Args.push_back(Entry);
52365237 RetTy = Type::getVoidTy(FTy->getContext());
52485249 Entry.Node = ArgNode; Entry.Ty = V->getType();
52495250
52505251 unsigned attrInd = i - CS.arg_begin() + 1;
5251 Entry.isSExt = CS.paramHasAttr(attrInd, Attribute::SExt);
5252 Entry.isZExt = CS.paramHasAttr(attrInd, Attribute::ZExt);
5253 Entry.isInReg = CS.paramHasAttr(attrInd, Attribute::InReg);
5254 Entry.isSRet = CS.paramHasAttr(attrInd, Attribute::StructRet);
5255 Entry.isNest = CS.paramHasAttr(attrInd, Attribute::Nest);
5256 Entry.isByVal = CS.paramHasAttr(attrInd, Attribute::ByVal);
5257 Entry.Alignment = CS.getParamAlignment(attrInd);
5252 Entry.isSExt = CS.paramHasAttr(attrInd, Attribute::SExt);
5253 Entry.isZExt = CS.paramHasAttr(attrInd, Attribute::ZExt);
5254 Entry.isInReg = CS.paramHasAttr(attrInd, Attribute::InReg);
5255 Entry.isSRet = CS.paramHasAttr(attrInd, Attribute::StructRet);
5256 Entry.isNest = CS.paramHasAttr(attrInd, Attribute::Nest);
5257 Entry.isByVal = CS.paramHasAttr(attrInd, Attribute::ByVal);
5258 Entry.isReturned = CS.paramHasAttr(attrInd, Attribute::Returned);
5259 Entry.Alignment = CS.getParamAlignment(attrInd);
52585260 Args.push_back(Entry);
52595261 }
52605262
64296431 }
64306432 if (Args[i].isNest)
64316433 Flags.setNest();
6434 if (Args[i].isReturned)
6435 Flags.setReturned();
64326436 Flags.setOrigAlign(OriginalAlignment);
64336437
64346438 MVT PartVT = getRegisterType(CLI.RetTy->getContext(), VT);
194194 return "readnone";
195195 if (hasAttribute(Attribute::ReadOnly))
196196 return "readonly";
197 if (hasAttribute(Attribute::Returned))
198 return "returned";
197199 if (hasAttribute(Attribute::ReturnsTwice))
198200 return "returns_twice";
199201 if (hasAttribute(Attribute::SExt))
392394 case Attribute::SanitizeThread: return 1ULL << 36;
393395 case Attribute::SanitizeMemory: return 1ULL << 37;
394396 case Attribute::NoBuiltin: return 1ULL << 38;
397 case Attribute::Returned: return 1ULL << 39;
395398 }
396399 llvm_unreachable("Unsupported attribute type");
397400 }
121121 return false; // StructRet param must be first param
122122 return getParent()->getAttributes().
123123 hasAttribute(1, Attribute::StructRet);
124 }
125
126 /// hasReturnedAttr - Return true if this argument has the returned attribute on
127 /// it in its containing function.
128 bool Argument::hasReturnedAttr() const {
129 return getParent()->getAttributes().
130 hasAttribute(getArgNo()+1, Attribute::Returned);
124131 }
125132
126133 /// addAttr - Add attributes to an argument.
693693 Assert1(!Attrs.hasAttribute(Idx, Attribute::ByVal) &&
694694 !Attrs.hasAttribute(Idx, Attribute::Nest) &&
695695 !Attrs.hasAttribute(Idx, Attribute::StructRet) &&
696 !Attrs.hasAttribute(Idx, Attribute::NoCapture),
697 "Attribute 'byval', 'nest', 'sret', and 'nocapture' "
696 !Attrs.hasAttribute(Idx, Attribute::NoCapture) &&
697 !Attrs.hasAttribute(Idx, Attribute::Returned),
698 "Attribute 'byval', 'nest', 'sret', 'nocapture', and 'returned' "
698699 "do not apply to return values!", V);
699700
700701 // Check for mutually incompatible attributes.
749750 return;
750751
751752 bool SawNest = false;
753 bool SawReturned = false;
752754
753755 for (unsigned i = 0, e = Attrs.getNumSlots(); i != e; ++i) {
754756 unsigned Idx = Attrs.getSlotIndex(i);
763765
764766 VerifyParameterAttrs(Attrs, Idx, Ty, Idx == 0, V);
765767
766 if (Attrs.hasAttribute(i, Attribute::Nest)) {
768 if (Idx == 0)
769 continue;
770
771 if (Attrs.hasAttribute(Idx, Attribute::Nest)) {
767772 Assert1(!SawNest, "More than one parameter has attribute nest!", V);
768773 SawNest = true;
774 }
775
776 if (Attrs.hasAttribute(Idx, Attribute::Returned)) {
777 Assert1(!SawReturned, "More than one parameter has attribute returned!",
778 V);
779 Assert1(Ty->canLosslesslyBitCastTo(FT->getReturnType()), "Incompatible "
780 "argument and return types for 'returned' attribute", V);
781 SawReturned = true;
769782 }
770783
771784 if (Attrs.hasAttribute(Idx, Attribute::StructRet))
13471360 // Verify call attributes.
13481361 VerifyFunctionAttrs(FTy, Attrs, I);
13491362
1350 if (FTy->isVarArg())
1363 if (FTy->isVarArg()) {
1364 // FIXME? is 'nest' even legal here?
1365 bool SawNest = false;
1366 bool SawReturned = false;
1367
1368 for (unsigned Idx = 1; Idx < 1 + FTy->getNumParams(); ++Idx) {
1369 if (Attrs.hasAttribute(Idx, Attribute::Nest))
1370 SawNest = true;
1371 if (Attrs.hasAttribute(Idx, Attribute::Returned))
1372 SawReturned = true;
1373 }
1374
13511375 // Check attributes on the varargs part.
13521376 for (unsigned Idx = 1 + FTy->getNumParams(); Idx <= CS.arg_size(); ++Idx) {
1353 VerifyParameterAttrs(Attrs, Idx, CS.getArgument(Idx-1)->getType(),
1354 false, I);
1377 Type *Ty = CS.getArgument(Idx-1)->getType();
1378 VerifyParameterAttrs(Attrs, Idx, Ty, false, I);
1379
1380 if (Attrs.hasAttribute(Idx, Attribute::Nest)) {
1381 Assert1(!SawNest, "More than one parameter has attribute nest!", I);
1382 SawNest = true;
1383 }
1384
1385 if (Attrs.hasAttribute(Idx, Attribute::Returned)) {
1386 Assert1(!SawReturned, "More than one parameter has attribute returned!",
1387 I);
1388 Assert1(Ty->canLosslesslyBitCastTo(FTy->getReturnType()),
1389 "Incompatible argument and return types for 'returned' "
1390 "attribute", I);
1391 SawReturned = true;
1392 }
13551393
13561394 Assert1(!Attrs.hasAttribute(Idx, Attribute::StructRet),
13571395 "Attribute 'sret' cannot be used for vararg call arguments!", I);
13581396 }
1397 }
13591398
13601399 // Verify that there's no metadata unless it's a direct call to an intrinsic.
13611400 if (CS.getCalledFunction() == 0 ||
7474 }
7575
7676 const uint32_t*
77 ARMBaseRegisterInfo::getThisReturnPreservedMask(CallingConv::ID) const {
78 return (STI.isTargetIOS() && !STI.isAAPCS_ABI())
79 ? CSR_iOS_ThisReturn_RegMask : CSR_AAPCS_ThisReturn_RegMask;
80 }
81
82 const uint32_t*
7783 ARMBaseRegisterInfo::getNoPreservedMask() const {
7884 return CSR_NoRegs_RegMask;
7985 }
9595 /// Code Generation virtual methods...
9696 const uint16_t *getCalleeSavedRegs(const MachineFunction *MF = 0) const;
9797 const uint32_t *getCallPreservedMask(CallingConv::ID) const;
98 const uint32_t *getThisReturnPreservedMask(CallingConv::ID) const;
9899 const uint32_t *getNoPreservedMask() const;
99100
100101 BitVector getReservedRegs(const MachineFunction &MF) const;
194194 def CSR_AAPCS : CalleeSavedRegs<(add LR, R11, R10, R9, R8, R7, R6, R5, R4,
195195 (sequence "D%u", 15, 8))>;
196196
197 // Constructors and destructors return 'this' in the ARM C++ ABI; since 'this'
198 // and the pointer return value are both passed in R0 in these cases, this can
199 // be partially modelled by treating R0 as a callee-saved register
200 // Only the resulting RegMask is used; the SaveList is ignored
201 def CSR_AAPCS_ThisReturn : CalleeSavedRegs<(add LR, R11, R10, R9, R8, R7, R6,
202 R5, R4, (sequence "D%u", 15, 8),
203 R0)>;
204
197205 // iOS ABI deviates from ARM standard ABI. R9 is not a callee-saved register.
198206 // Also save R7-R4 first to match the stack frame fixed spill areas.
199207 def CSR_iOS : CalleeSavedRegs<(add LR, R7, R6, R5, R4, (sub CSR_AAPCS, R9))>;
208
209 def CSR_iOS_ThisReturn : CalleeSavedRegs<(add LR, R7, R6, R5, R4,
210 (sub CSR_AAPCS_ThisReturn, R9))>;
200211
201212 // GHC set of callee saved regs is empty as all those regs are
202213 // used for passing STG regs around
12371237 CallingConv::ID CallConv, bool isVarArg,
12381238 const SmallVectorImpl &Ins,
12391239 DebugLoc dl, SelectionDAG &DAG,
1240 SmallVectorImpl &InVals) const {
1240 SmallVectorImpl &InVals,
1241 bool isThisReturn, SDValue ThisVal) const {
12411242
12421243 // Assign locations to each value returned by this call.
12431244 SmallVector RVLocs;
12501251 // Copy all of the result registers out of their specified physreg.
12511252 for (unsigned i = 0; i != RVLocs.size(); ++i) {
12521253 CCValAssign VA = RVLocs[i];
1254
1255 // Pass 'this' value directly from the argument to return value, to avoid
1256 // reg unit interference
1257 if (i == 0 && isThisReturn) {
1258 assert(!VA.needsCustom() && VA.getLocVT() == MVT::i32);
1259 InVals.push_back(ThisVal);
1260 continue;
1261 }
12531262
12541263 SDValue Val;
12551264 if (VA.needsCustom()) {
13631372
13641373 MachineFunction &MF = DAG.getMachineFunction();
13651374 bool IsStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet();
1366 bool IsSibCall = false;
1375 bool IsThisReturn = false;
1376 bool IsSibCall = false;
13671377 // Disable tail calls if they're not supported.
13681378 if (!EnableARMTailCalls && !Subtarget->supportsTailCall())
13691379 isTailCall = false;
14591469 StackPtr, MemOpChains, Flags);
14601470 }
14611471 } else if (VA.isRegLoc()) {
1472 if (realArgIdx == 0 && Flags.isReturned() && VA.getLocVT() == MVT::i32) {
1473 assert(!Ins.empty() && Ins[0].VT == Outs[0].VT &&
1474 "unexpected use of 'returned'");
1475 IsThisReturn = true;
1476 }
14621477 RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
14631478 } else if (isByVal) {
14641479 assert(VA.isMemLoc());
16791694 RegsToPass[i].second.getValueType()));
16801695
16811696 // Add a register mask operand representing the call-preserved registers.
1697 const uint32_t *Mask;
16821698 const TargetRegisterInfo *TRI = getTargetMachine().getRegisterInfo();
1683 const uint32_t *Mask = TRI->getCallPreservedMask(CallConv);
1699 const ARMBaseRegisterInfo *ARI = static_cast(TRI);
1700 if (IsThisReturn)
1701 // For 'this' returns, use the R0-preserving mask
1702 Mask = ARI->getThisReturnPreservedMask(CallConv);
1703 else
1704 Mask = ARI->getCallPreservedMask(CallConv);
1705
16841706 assert(Mask && "Missing call preserved mask for calling convention");
16851707 Ops.push_back(DAG.getRegisterMask(Mask));
16861708
17021724
17031725 // Handle result values, copying them out of physregs into vregs that we
17041726 // return.
1705 return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins,
1706 dl, DAG, InVals);
1727 return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins, dl, DAG,
1728 InVals, IsThisReturn,
1729 IsThisReturn ? OutVals[0] : SDValue());
17071730 }
17081731
17091732 /// HandleByVal - Every parameter *after* a byval parameter is passed
463463 CallingConv::ID CallConv, bool isVarArg,
464464 const SmallVectorImpl &Ins,
465465 DebugLoc dl, SelectionDAG &DAG,
466 SmallVectorImpl &InVals) const;
466 SmallVectorImpl &InVals,
467 bool isThisReturn, SDValue ThisVal) const;
467468
468469 virtual SDValue
469470 LowerFormalArguments(SDValue Chain,
0 ; RUN: llc < %s -mtriple=armv6-linux-gnueabi -arm-tail-calls | FileCheck %s -check-prefix=CHECKELF
1 ; RUN: llc < %s -mtriple=thumbv7-apple-ios -arm-tail-calls | FileCheck %s -check-prefix=CHECKT2D
2
3 %struct.A = type { i8 }
4 %struct.B = type { i32 }
5 %struct.C = type { %struct.B }
6 %struct.D = type { %struct.B }
7
8 declare %struct.A* @A_ctor_base(%struct.A* returned)
9 declare %struct.B* @B_ctor_base(%struct.B* returned, i32)
10 declare %struct.B* @B_ctor_complete(%struct.B* returned, i32)
11
12 declare %struct.A* @A_ctor_base_nothisret(%struct.A*)
13 declare %struct.B* @B_ctor_base_nothisret(%struct.B*, i32)
14 declare %struct.B* @B_ctor_complete_nothisret(%struct.B*, i32)
15
16 define %struct.C* @C_ctor_base(%struct.C* returned %this, i32 %x) {
17 entry:
18 ; CHECKELF: C_ctor_base:
19 ; CHECKELF-NOT: mov {{r[0-9]+}}, r0
20 ; CHECKELF: bl A_ctor_base
21 ; CHECKELF-NOT: mov r0, {{r[0-9]+}}
22 ; CHECKELF: b B_ctor_base
23 ; CHECKT2D: C_ctor_base:
24 ; CHECKT2D-NOT: mov {{r[0-9]+}}, r0
25 ; CHECKT2D: blx _A_ctor_base
26 ; CHECKT2D-NOT: mov r0, {{r[0-9]+}}
27 ; CHECKT2D: b.w _B_ctor_base
28 %0 = bitcast %struct.C* %this to %struct.A*
29 %call = tail call %struct.A* @A_ctor_base(%struct.A* %0)
30 %1 = getelementptr inbounds %struct.C* %this, i32 0, i32 0
31 %call2 = tail call %struct.B* @B_ctor_base(%struct.B* %1, i32 %x)
32 ret %struct.C* %this
33 }
34
35 define %struct.C* @C_ctor_base_nothisret(%struct.C* %this, i32 %x) {
36 entry:
37 ; CHECKELF: C_ctor_base_nothisret:
38 ; CHECKELF: mov [[SAVETHIS:r[0-9]+]], r0
39 ; CHECKELF: bl A_ctor_base_nothisret
40 ; CHECKELF: mov r0, [[SAVETHIS]]
41 ; CHECKELF-NOT: b B_ctor_base_nothisret
42 ; CHECKT2D: C_ctor_base_nothisret:
43 ; CHECKT2D: mov [[SAVETHIS:r[0-9]+]], r0
44 ; CHECKT2D: blx _A_ctor_base_nothisret
45 ; CHECKT2D: mov r0, [[SAVETHIS]]
46 ; CHECKT2D-NOT: b.w _B_ctor_base_nothisret
47 %0 = bitcast %struct.C* %this to %struct.A*
48 %call = tail call %struct.A* @A_ctor_base_nothisret(%struct.A* %0)
49 %1 = getelementptr inbounds %struct.C* %this, i32 0, i32 0
50 %call2 = tail call %struct.B* @B_ctor_base_nothisret(%struct.B* %1, i32 %x)
51 ret %struct.C* %this
52 }
53
54 define %struct.C* @C_ctor_complete(%struct.C* %this, i32 %x) {
55 entry:
56 ; CHECKELF: C_ctor_complete:
57 ; CHECKELF: b C_ctor_base
58 ; CHECKT2D: C_ctor_complete:
59 ; CHECKT2D: b.w _C_ctor_base
60 %call = tail call %struct.C* @C_ctor_base(%struct.C* %this, i32 %x)
61 ret %struct.C* %this
62 }
63
64 define %struct.C* @C_ctor_complete_nothisret(%struct.C* %this, i32 %x) {
65 entry:
66 ; CHECKELF: C_ctor_complete_nothisret:
67 ; CHECKELF-NOT: b C_ctor_base_nothisret
68 ; CHECKT2D: C_ctor_complete_nothisret:
69 ; CHECKT2D-NOT: b.w _C_ctor_base_nothisret
70 %call = tail call %struct.C* @C_ctor_base_nothisret(%struct.C* %this, i32 %x)
71 ret %struct.C* %this
72 }
73
74 define %struct.D* @D_ctor_base(%struct.D* %this, i32 %x) {
75 entry:
76 ; CHECKELF: D_ctor_base:
77 ; CHECKELF-NOT: mov {{r[0-9]+}}, r0
78 ; CHECKELF: bl B_ctor_complete
79 ; CHECKELF-NOT: mov r0, {{r[0-9]+}}
80 ; CHECKELF: b B_ctor_complete
81 ; CHECKT2D: D_ctor_base:
82 ; CHECKT2D-NOT: mov {{r[0-9]+}}, r0
83 ; CHECKT2D: blx _B_ctor_complete
84 ; CHECKT2D-NOT: mov r0, {{r[0-9]+}}
85 ; CHECKT2D: b.w _B_ctor_complete
86 %b = getelementptr inbounds %struct.D* %this, i32 0, i32 0
87 %call = tail call %struct.B* @B_ctor_complete(%struct.B* %b, i32 %x)
88 %call2 = tail call %struct.B* @B_ctor_complete(%struct.B* %b, i32 %x)
89 ret %struct.D* %this
90 }
0 ; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck %s
1
2 %struct.A = type { i8 }
3 %struct.B = type { i32 }
4 %struct.C = type { %struct.B }
5 %struct.D = type { %struct.B }
6 %struct.E = type { %struct.B }
7
8 declare %struct.A* @A_ctor(%struct.A* returned)
9 declare %struct.B* @B_ctor(%struct.B* returned, i32)
10
11 declare %struct.A* @A_ctor_nothisret(%struct.A*)
12 declare %struct.B* @B_ctor_nothisret(%struct.B*, i32)
13
14 define %struct.C* @C_ctor(%struct.C* %this, i32 %y) {
15 entry:
16 ; CHECK: C_ctor:
17 ; CHECK: jmp B_ctor # TAILCALL
18 %0 = getelementptr inbounds %struct.C* %this, i64 0, i32 0
19 %call = tail call %struct.B* @B_ctor(%struct.B* %0, i32 %y)
20 ret %struct.C* %this
21 }
22
23 define %struct.C* @C_ctor_nothisret(%struct.C* %this, i32 %y) {
24 entry:
25 ; CHECK: C_ctor_nothisret:
26 ; CHECK-NOT: jmp B_ctor_nothisret
27 %0 = getelementptr inbounds %struct.C* %this, i64 0, i32 0
28 %call = tail call %struct.B* @B_ctor_nothisret(%struct.B* %0, i32 %y)
29 ret %struct.C* %this
30 }
31
32 define %struct.D* @D_ctor(%struct.D* %this, i32 %y) {
33 entry:
34 ; CHECK: D_ctor:
35 ; CHECK: movq %rcx, [[SAVETHIS:%r[0-9a-z]+]]
36 ; CHECK: callq A_ctor
37 ; CHECK: movq [[SAVETHIS]], %rcx
38 ; CHECK: jmp B_ctor # TAILCALL
39 %0 = bitcast %struct.D* %this to %struct.A*
40 %call = tail call %struct.A* @A_ctor(%struct.A* %0)
41 %1 = getelementptr inbounds %struct.D* %this, i64 0, i32 0
42 %call2 = tail call %struct.B* @B_ctor(%struct.B* %1, i32 %y)
43 ; (this next line would never be generated by Clang, actually)
44 %2 = bitcast %struct.A* %call to %struct.D*
45 ret %struct.D* %2
46 }
47
48 define %struct.D* @D_ctor_nothisret(%struct.D* %this, i32 %y) {
49 entry:
50 ; CHECK: D_ctor_nothisret:
51 ; CHECK: movq %rcx, [[SAVETHIS:%r[0-9a-z]+]]
52 ; CHECK: callq A_ctor_nothisret
53 ; CHECK: movq [[SAVETHIS]], %rcx
54 ; CHECK-NOT: jmp B_ctor_nothisret
55 %0 = bitcast %struct.D* %this to %struct.A*
56 %call = tail call %struct.A* @A_ctor_nothisret(%struct.A* %0)
57 %1 = getelementptr inbounds %struct.D* %this, i64 0, i32 0
58 %call2 = tail call %struct.B* @B_ctor_nothisret(%struct.B* %1, i32 %y)
59 ; (this next line would never be generated by Clang, actually)
60 %2 = bitcast %struct.A* %call to %struct.D*
61 ret %struct.D* %2
62 }
63
64 define %struct.E* @E_ctor(%struct.E* %this, i32 %x) {
65 entry:
66 ; CHECK: E_ctor:
67 ; CHECK: movq %rcx, [[SAVETHIS:%r[0-9a-z]+]]
68 ; CHECK: callq B_ctor
69 ; CHECK: movq [[SAVETHIS]], %rcx
70 ; CHECK: jmp B_ctor # TAILCALL
71 %b = getelementptr inbounds %struct.E* %this, i64 0, i32 0
72 %call = tail call %struct.B* @B_ctor(%struct.B* %b, i32 %x)
73 %call4 = tail call %struct.B* @B_ctor(%struct.B* %b, i32 %x)
74 ret %struct.E* %this
75 }
76
77 define %struct.E* @E_ctor_nothisret(%struct.E* %this, i32 %x) {
78 entry:
79 ; CHECK: E_ctor_nothisret:
80 ; CHECK: movq %rcx, [[SAVETHIS:%r[0-9a-z]+]]
81 ; CHECK: callq B_ctor_nothisret
82 ; CHECK: movq [[SAVETHIS]], %rcx
83 ; CHECK-NOT: jmp B_ctor_nothisret
84 %b = getelementptr inbounds %struct.E* %this, i64 0, i32 0
85 %call = tail call %struct.B* @B_ctor_nothisret(%struct.B* %b, i32 %x)
86 %call4 = tail call %struct.B* @B_ctor_nothisret(%struct.B* %b, i32 %x)
87 ret %struct.E* %this
88 }