llvm.org GIT mirror llvm / 324b3fc
[FastISel] Add basic infrastructure to support a target-independent call lowering hook in FastISel. WIP The infrastructure mimics the call lowering we have already in place for SelectionDAG, but with limitations. For example structure return demotion and non-simple types are not supported (yet). Currently every backend has its own implementation and duplicated code for call lowering. There is also no specified interface that could be called from target-independent code. The target-hook is opt-in and doesn't affect current implementations. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212848 91177308-0d34-0410-b5e6-96231b3b80d8 Juergen Ributzka 5 years ago
2 changed file(s) with 361 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
1515 #define LLVM_CODEGEN_FASTISEL_H
1616
1717 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/CodeGen/CallingConvLower.h"
1819 #include "llvm/CodeGen/MachineBasicBlock.h"
20 #include "llvm/Target/TargetLowering.h"
21 #include "llvm/IR/CallingConv.h"
1922
2023 namespace llvm {
2124
4649 /// This is a fast-path instruction selection class that generates poor code and
4750 /// doesn't support illegal types or non-trivial lowering, but runs quickly.
4851 class FastISel {
52 public:
53 struct ArgListEntry {
54 Value *Val;
55 Type *Ty;
56 bool isSExt : 1;
57 bool isZExt : 1;
58 bool isInReg : 1;
59 bool isSRet : 1;
60 bool isNest : 1;
61 bool isByVal : 1;
62 bool isInAlloca : 1;
63 bool isReturned : 1;
64 uint16_t Alignment;
65
66 ArgListEntry()
67 : Val(nullptr), Ty(nullptr), isSExt(false), isZExt(false), isInReg(false),
68 isSRet(false), isNest(false), isByVal(false), isInAlloca(false),
69 isReturned(false), Alignment(0) { }
70
71 void setAttributes(ImmutableCallSite *CS, unsigned AttrIdx);
72 };
73 typedef std::vector ArgListTy;
74
75 struct CallLoweringInfo {
76 Type *RetTy;
77 bool RetSExt : 1;
78 bool RetZExt : 1;
79 bool IsVarArg : 1;
80 bool IsInReg : 1;
81 bool DoesNotReturn : 1;
82 bool IsReturnValueUsed : 1;
83
84 // IsTailCall should be modified by implementations of
85 // FastLowerCall that perform tail call conversions.
86 bool IsTailCall;
87
88 unsigned NumFixedArgs;
89 CallingConv::ID CallConv;
90 const Value *Callee;
91 const char *SymName;
92 ArgListTy Args;
93 ImmutableCallSite *CS;
94 MachineInstr *Call;
95 unsigned ResultReg;
96 unsigned NumResultRegs;
97
98 SmallVector OutVals;
99 SmallVector OutFlags;
100 SmallVector OutRegs;
101 SmallVector Ins;
102 SmallVector InRegs;
103
104 CallLoweringInfo()
105 : RetTy(nullptr), RetSExt(false), RetZExt(false), IsVarArg(false),
106 IsInReg(false), DoesNotReturn(false), IsReturnValueUsed(true),
107 IsTailCall(false), NumFixedArgs(-1), CallConv(CallingConv::C),
108 Callee(nullptr), SymName(nullptr), CS(nullptr), Call(nullptr),
109 ResultReg(0), NumResultRegs(0)
110 {}
111
112 CallLoweringInfo &setCallee(Type *ResultTy, FunctionType *FuncTy,
113 const Value *Target, ArgListTy &&ArgsList,
114 ImmutableCallSite &Call) {
115 RetTy = ResultTy;
116 Callee = Target;
117
118 IsInReg = Call.paramHasAttr(0, Attribute::InReg);
119 DoesNotReturn = Call.doesNotReturn();
120 IsVarArg = FuncTy->isVarArg();
121 IsReturnValueUsed = !Call.getInstruction()->use_empty();
122 RetSExt = Call.paramHasAttr(0, Attribute::SExt);
123 RetZExt = Call.paramHasAttr(0, Attribute::ZExt);
124
125 CallConv = Call.getCallingConv();
126 NumFixedArgs = FuncTy->getNumParams();
127 Args = std::move(ArgsList);
128
129 CS = &Call;
130
131 return *this;
132 }
133
134 CallLoweringInfo &setCallee(Type *ResultTy, FunctionType *FuncTy,
135 const char *Target, ArgListTy &&ArgsList,
136 ImmutableCallSite &Call,
137 unsigned FixedArgs = ~0U) {
138 RetTy = ResultTy;
139 Callee = Call.getCalledValue();
140 SymName = Target;
141
142 IsInReg = Call.paramHasAttr(0, Attribute::InReg);
143 DoesNotReturn = Call.doesNotReturn();
144 IsVarArg = FuncTy->isVarArg();
145 IsReturnValueUsed = !Call.getInstruction()->use_empty();
146 RetSExt = Call.paramHasAttr(0, Attribute::SExt);
147 RetZExt = Call.paramHasAttr(0, Attribute::ZExt);
148
149 CallConv = Call.getCallingConv();
150 NumFixedArgs = (FixedArgs == ~0U) ? FuncTy->getNumParams() : FixedArgs;
151 Args = std::move(ArgsList);
152
153 CS = &Call;
154
155 return *this;
156 }
157
158 CallLoweringInfo &setCallee(CallingConv::ID CC, Type *ResultTy,
159 const Value *Target, ArgListTy &&ArgsList,
160 unsigned FixedArgs = ~0U) {
161 RetTy = ResultTy;
162 Callee = Target;
163 CallConv = CC;
164 NumFixedArgs = (FixedArgs == ~0U) ? Args.size() : FixedArgs;
165 Args = std::move(ArgsList);
166 return *this;
167 }
168
169 CallLoweringInfo &setTailCall(bool Value = true) {
170 IsTailCall = Value;
171 return *this;
172 }
173
174 ArgListTy &getArgs() {
175 return Args;
176 }
177
178 void clearOuts() {
179 OutVals.clear();
180 OutFlags.clear();
181 OutRegs.clear();
182 }
183
184 void clearIns() {
185 Ins.clear();
186 InRegs.clear();
187 }
188 };
189
49190 protected:
50191 DenseMap LocalValueMap;
51192 FunctionLoweringInfo &FuncInfo;
172313 /// process fails to select an instruction. This gives targets a chance to
173314 /// emit code for anything that doesn't fit into FastISel's framework. It
174315 /// returns true if it was successful.
175 virtual bool
176 TargetSelectInstruction(const Instruction *I) = 0;
316 virtual bool TargetSelectInstruction(const Instruction *I) = 0;
177317
178318 /// This method is called by target-independent code to do target specific
179319 /// argument lowering. It returns true if it was successful.
180320 virtual bool FastLowerArguments();
181321
182 /// This method is called by target-independent code to do target specific
183 /// intrinsic lowering. It returns true if it was successful.
322 /// \brief This method is called by target-independent code to do target
323 /// specific call lowering. It returns true if it was successful.
324 virtual bool FastLowerCall(CallLoweringInfo &CLI);
325
326 /// \brief This method is called by target-independent code to do target
327 /// specific intrinsic lowering. It returns true if it was successful.
184328 virtual bool FastLowerIntrinsicCall(const IntrinsicInst *II);
185329
186330 /// This method is called by target-independent code to request that an
385529 /// \brief Create a machine mem operand from the given instruction.
386530 MachineMemOperand *createMachineMemOperandFor(const Instruction *I) const;
387531
532 bool LowerCallTo(const CallInst *CI, const char *SymName, unsigned NumArgs);
533 bool LowerCallTo(CallLoweringInfo &CLI);
534
388535 private:
389536 bool SelectBinaryOp(const User *I, unsigned ISDOpcode);
390537
393540 bool SelectGetElementPtr(const User *I);
394541
395542 bool SelectStackmap(const CallInst *I);
396 bool SelectCall(const User *I);
543 bool LowerCall(const CallInst *I);
544 bool SelectCall(const User *Call);
397545 bool SelectIntrinsicCall(const IntrinsicInst *II);
398546
399547 bool SelectBitCast(const User *I);
3838 //
3939 //===----------------------------------------------------------------------===//
4040
41 #include "llvm/CodeGen/Analysis.h"
4142 #include "llvm/CodeGen/FastISel.h"
4243 #include "llvm/ADT/Optional.h"
4344 #include "llvm/ADT/Statistic.h"
7273 STATISTIC(NumFastIselSuccessTarget, "Number of insts selected by "
7374 "target-specific selector");
7475 STATISTIC(NumFastIselDead, "Number of dead insts removed on failure");
76
77 /// \brief Set CallLoweringInfo attribute flags based on a call instruction
78 /// and called function attributes.
79 void FastISel::ArgListEntry::setAttributes(ImmutableCallSite *CS,
80 unsigned AttrIdx) {
81 isSExt = CS->paramHasAttr(AttrIdx, Attribute::SExt);
82 isZExt = CS->paramHasAttr(AttrIdx, Attribute::ZExt);
83 isInReg = CS->paramHasAttr(AttrIdx, Attribute::InReg);
84 isSRet = CS->paramHasAttr(AttrIdx, Attribute::StructRet);
85 isNest = CS->paramHasAttr(AttrIdx, Attribute::Nest);
86 isByVal = CS->paramHasAttr(AttrIdx, Attribute::ByVal);
87 isInAlloca = CS->paramHasAttr(AttrIdx, Attribute::InAlloca);
88 isReturned = CS->paramHasAttr(AttrIdx, Attribute::Returned);
89 Alignment = CS->getParamAlignment(AttrIdx);
90 }
7591
7692 /// startNewBlock - Set the current block to which generated machine
7793 /// instructions will be appended, and clear the local CSE map.
661677 return true;
662678 }
663679
680 /// Returns an AttributeSet representing the attributes applied to the return
681 /// value of the given call.
682 static AttributeSet getReturnAttrs(FastISel::CallLoweringInfo &CLI) {
683 SmallVector Attrs;
684 if (CLI.RetSExt)
685 Attrs.push_back(Attribute::SExt);
686 if (CLI.RetZExt)
687 Attrs.push_back(Attribute::ZExt);
688 if (CLI.IsInReg)
689 Attrs.push_back(Attribute::InReg);
690
691 return AttributeSet::get(CLI.RetTy->getContext(), AttributeSet::ReturnIndex,
692 Attrs);
693 }
694
695 bool FastISel::LowerCallTo(const CallInst *CI, const char *SymName,
696 unsigned NumArgs) {
697 ImmutableCallSite CS(CI);
698
699 PointerType *PT = cast(CS.getCalledValue()->getType());
700 FunctionType *FTy = cast(PT->getElementType());
701 Type *RetTy = FTy->getReturnType();
702
703 ArgListTy Args;
704 Args.reserve(NumArgs);
705
706 // Populate the argument list.
707 // Attributes for args start at offset 1, after the return attribute.
708 for (unsigned ArgI = 0; ArgI != NumArgs; ++ArgI) {
709 Value *V = CI->getOperand(ArgI);
710
711 assert(!V->getType()->isEmptyTy() && "Empty type passed to intrinsic.");
712
713 ArgListEntry Entry;
714 Entry.Val = V;
715 Entry.Ty = V->getType();
716 Entry.setAttributes(&CS, ArgI + 1);
717 Args.push_back(Entry);
718 }
719
720 CallLoweringInfo CLI;
721 CLI.setCallee(RetTy, FTy, SymName, std::move(Args), CS, NumArgs);
722
723 return LowerCallTo(CLI);
724 }
725
726 bool FastISel::LowerCallTo(CallLoweringInfo &CLI) {
727 // Handle the incoming return values from the call.
728 CLI.clearIns();
729 SmallVector RetTys;
730 ComputeValueVTs(TLI, CLI.RetTy, RetTys);
731
732 SmallVector Outs;
733 GetReturnInfo(CLI.RetTy, getReturnAttrs(CLI), Outs, TLI);
734
735 bool CanLowerReturn = TLI.CanLowerReturn(CLI.CallConv, *FuncInfo.MF,
736 CLI.IsVarArg, Outs,
737 CLI.RetTy->getContext());
738
739 // FIXME: sret demotion isn't supported yet - bail out.
740 if (!CanLowerReturn)
741 return false;
742
743 for (unsigned I = 0, E = RetTys.size(); I != E; ++I) {
744 EVT VT = RetTys[I];
745 MVT RegisterVT = TLI.getRegisterType(CLI.RetTy->getContext(), VT);
746 unsigned NumRegs = TLI.getNumRegisters(CLI.RetTy->getContext(), VT);
747 for (unsigned i = 0; i != NumRegs; ++i) {
748 ISD::InputArg MyFlags;
749 MyFlags.VT = RegisterVT;
750 MyFlags.ArgVT = VT;
751 MyFlags.Used = CLI.IsReturnValueUsed;
752 if (CLI.RetSExt)
753 MyFlags.Flags.setSExt();
754 if (CLI.RetZExt)
755 MyFlags.Flags.setZExt();
756 if (CLI.IsInReg)
757 MyFlags.Flags.setInReg();
758 CLI.Ins.push_back(MyFlags);
759 }
760 }
761
762 // Handle all of the outgoing arguments.
763 CLI.clearOuts();
764 for (auto &Arg : CLI.getArgs()) {
765 Type *FinalType = Arg.Ty;
766 if (Arg.isByVal)
767 FinalType = cast(Arg.Ty)->getElementType();
768 bool NeedsRegBlock = TLI.functionArgumentNeedsConsecutiveRegisters(
769 FinalType, CLI.CallConv, CLI.IsVarArg);
770
771 ISD::ArgFlagsTy Flags;
772 if (Arg.isZExt)
773 Flags.setZExt();
774 if (Arg.isSExt)
775 Flags.setSExt();
776 if (Arg.isInReg)
777 Flags.setInReg();
778 if (Arg.isSRet)
779 Flags.setSRet();
780 if (Arg.isByVal)
781 Flags.setByVal();
782 if (Arg.isInAlloca) {
783 Flags.setInAlloca();
784 // Set the byval flag for CCAssignFn callbacks that don't know about
785 // inalloca. This way we can know how many bytes we should've allocated
786 // and how many bytes a callee cleanup function will pop. If we port
787 // inalloca to more targets, we'll have to add custom inalloca handling in
788 // the various CC lowering callbacks.
789 Flags.setByVal();
790 }
791 if (Arg.isByVal || Arg.isInAlloca) {
792 PointerType *Ty = cast(Arg.Ty);
793 Type *ElementTy = Ty->getElementType();
794 unsigned FrameSize = DL.getTypeAllocSize(ElementTy);
795 // For ByVal, alignment should come from FE. BE will guess if this info is
796 // not there, but there are cases it cannot get right.
797 unsigned FrameAlign = Arg.Alignment;
798 if (!FrameAlign)
799 FrameAlign = TLI.getByValTypeAlignment(ElementTy);
800 Flags.setByValSize(FrameSize);
801 Flags.setByValAlign(FrameAlign);
802 }
803 if (Arg.isNest)
804 Flags.setNest();
805 if (NeedsRegBlock)
806 Flags.setInConsecutiveRegs();
807 unsigned OriginalAlignment = DL.getABITypeAlignment(Arg.Ty);
808 Flags.setOrigAlign(OriginalAlignment);
809
810 CLI.OutVals.push_back(Arg.Val);
811 CLI.OutFlags.push_back(Flags);
812 }
813
814 if (!FastLowerCall(CLI))
815 return false;
816
817 // Set all unused physreg defs as dead.
818 assert(CLI.Call && "No call instruction specified.");
819 CLI.Call->setPhysRegsDeadExcept(CLI.InRegs, TRI);
820
821 if (CLI.NumResultRegs && CLI.CS)
822 UpdateValueMap(CLI.CS->getInstruction(), CLI.ResultReg, CLI.NumResultRegs);
823
824 return true;
825 }
826
827 bool FastISel::LowerCall(const CallInst *CI) {
828 ImmutableCallSite CS(CI);
829
830 PointerType *PT = cast(CS.getCalledValue()->getType());
831 FunctionType *FuncTy = cast(PT->getElementType());
832 Type *RetTy = FuncTy->getReturnType();
833
834 ArgListTy Args;
835 ArgListEntry Entry;
836 Args.reserve(CS.arg_size());
837
838 for (ImmutableCallSite::arg_iterator i = CS.arg_begin(), e = CS.arg_end();
839 i != e; ++i) {
840 Value *V = *i;
841
842 // Skip empty types
843 if (V->getType()->isEmptyTy())
844 continue;
845
846 Entry.Val = V;
847 Entry.Ty = V->getType();
848
849 // Skip the first return-type Attribute to get to params.
850 Entry.setAttributes(&CS, i - CS.arg_begin() + 1);
851 Args.push_back(Entry);
852 }
853
854 // Check if target-independent constraints permit a tail call here.
855 // Target-dependent constraints are checked within FastLowerCall.
856 bool IsTailCall = CI->isTailCall();
857 if (IsTailCall && !isInTailCallPosition(CS, TM, TLI))
858 IsTailCall = false;
859
860 CallLoweringInfo CLI;
861 CLI.setCallee(RetTy, FuncTy, CI->getCalledValue(), std::move(Args), CS)
862 .setTailCall(IsTailCall);
863
864 return LowerCallTo(CLI);
865 }
866
664867 bool FastISel::SelectCall(const User *I) {
665868 const CallInst *Call = cast(I);
666869
699902 // since they tend to be inlined.
700903 flushLocalValueMap();
701904
702 // An arbitrary call. Bail.
703 return false;
905 return LowerCall(Call);
704906 }
705907
706908 bool FastISel::SelectIntrinsicCall(const IntrinsicInst *II) {
12281430 return false;
12291431 }
12301432
1433 bool FastISel::FastLowerCall(CallLoweringInfo &/*CLI*/) {
1434 return false;
1435 }
1436
12311437 bool FastISel::FastLowerIntrinsicCall(const IntrinsicInst */*II*/) {
12321438 return false;
12331439 }