1 //===- subzero/src/IceTargetLowering.cpp - Basic lowering implementation --===//
3 // The Subzero Code Generator
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the skeleton of the TargetLowering class,
11 // specifically invoking the appropriate lowering method for a given
12 // instruction kind and driving global register allocation. It also
13 // implements the non-deleted instruction iteration in
16 //===----------------------------------------------------------------------===//
18 #include "IceAssemblerARM32.h"
19 #include "IceAssemblerX8632.h"
20 #include "assembler_mips32.h"
21 #include "IceCfg.h" // setError()
22 #include "IceCfgNode.h"
23 #include "IceOperand.h"
24 #include "IceRegAlloc.h"
25 #include "IceTargetLowering.h"
26 #include "IceTargetLoweringARM32.h"
27 #include "IceTargetLoweringMIPS32.h"
28 #include "IceTargetLoweringX8632.h"
32 void LoweringContext::init(CfgNode *N) {
34 End = getNode()->getInsts().end();
39 void LoweringContext::rewind() {
40 Begin = getNode()->getInsts().begin();
46 void LoweringContext::insert(Inst *Inst) {
47 getNode()->getInsts().insert(Next, Inst);
51 void LoweringContext::skipDeleted(InstList::iterator &I) const {
52 while (I != End && I->isDeleted())
56 void LoweringContext::advanceForward(InstList::iterator &I) const {
63 Inst *LoweringContext::getLastInserted() const {
68 TargetLowering *TargetLowering::createLowering(TargetArch Target, Cfg *Func) {
69 #define SUBZERO_TARGET(X) \
70 if (Target == Target_##X) \
71 return Target##X::create(Func);
72 #include "llvm/Config/SZTargets.def"
74 Func->setError("Unsupported target");
78 TargetLowering::TargetLowering(Cfg *Func)
79 : Func(Func), Ctx(Func->getContext()), HasComputedFrame(false),
80 CallsReturnsTwice(false), StackAdjustment(0), NextLabelNumber(0),
81 Context(), SnapshotStackAdjustment(0) {}
83 std::unique_ptr<Assembler> TargetLowering::createAssembler(TargetArch Target,
85 #define SUBZERO_TARGET(X) \
86 if (Target == Target_##X) \
87 return std::unique_ptr<Assembler>(new X::Assembler##X());
88 #include "llvm/Config/SZTargets.def"
90 Func->setError("Unsupported target assembler");
94 void TargetLowering::doAddressOpt() {
95 if (llvm::isa<InstLoad>(*Context.getCur()))
97 else if (llvm::isa<InstStore>(*Context.getCur()))
100 Context.advanceNext();
103 void TargetLowering::doNopInsertion() {
104 Inst *I = Context.getCur();
105 bool ShouldSkip = llvm::isa<InstFakeUse>(I) || llvm::isa<InstFakeDef>(I) ||
106 llvm::isa<InstFakeKill>(I) || I->isRedundantAssign() ||
109 int Probability = Ctx->getFlags().getNopProbabilityAsPercentage();
110 for (int I = 0; I < Ctx->getFlags().getMaxNopsPerInstruction(); ++I) {
111 randomlyInsertNop(Probability / 100.0);
116 // Lowers a single instruction according to the information in
117 // Context, by checking the Context.Cur instruction kind and calling
118 // the appropriate lowering method. The lowering method should insert
119 // target instructions at the Cur.Next insertion point, and should not
120 // delete the Context.Cur instruction or advance Context.Cur.
122 // The lowering method may look ahead in the instruction stream as
123 // desired, and lower additional instructions in conjunction with the
124 // current one, for example fusing a compare and branch. If it does,
125 // it should advance Context.Cur to point to the next non-deleted
126 // instruction to process, and it should delete any additional
127 // instructions it consumes.
128 void TargetLowering::lower() {
129 assert(!Context.atEnd());
130 Inst *Inst = Context.getCur();
131 Inst->deleteIfDead();
132 if (!Inst->isDeleted()) {
133 // Mark the current instruction as deleted before lowering,
134 // otherwise the Dest variable will likely get marked as non-SSA.
135 // See Variable::setDefinition().
137 switch (Inst->getKind()) {
139 lowerAlloca(llvm::cast<InstAlloca>(Inst));
141 case Inst::Arithmetic:
142 lowerArithmetic(llvm::cast<InstArithmetic>(Inst));
145 lowerAssign(llvm::cast<InstAssign>(Inst));
148 lowerBr(llvm::cast<InstBr>(Inst));
151 lowerCall(llvm::cast<InstCall>(Inst));
154 lowerCast(llvm::cast<InstCast>(Inst));
156 case Inst::ExtractElement:
157 lowerExtractElement(llvm::cast<InstExtractElement>(Inst));
160 lowerFcmp(llvm::cast<InstFcmp>(Inst));
163 lowerIcmp(llvm::cast<InstIcmp>(Inst));
165 case Inst::InsertElement:
166 lowerInsertElement(llvm::cast<InstInsertElement>(Inst));
168 case Inst::IntrinsicCall: {
169 InstIntrinsicCall *Call = llvm::cast<InstIntrinsicCall>(Inst);
170 if (Call->getIntrinsicInfo().ReturnsTwice)
171 setCallsReturnsTwice(true);
172 lowerIntrinsicCall(Call);
176 lowerLoad(llvm::cast<InstLoad>(Inst));
179 lowerPhi(llvm::cast<InstPhi>(Inst));
182 lowerRet(llvm::cast<InstRet>(Inst));
185 lowerSelect(llvm::cast<InstSelect>(Inst));
188 lowerStore(llvm::cast<InstStore>(Inst));
191 lowerSwitch(llvm::cast<InstSwitch>(Inst));
193 case Inst::Unreachable:
194 lowerUnreachable(llvm::cast<InstUnreachable>(Inst));
196 case Inst::BundleLock:
197 case Inst::BundleUnlock:
202 // These are all Target instruction types and shouldn't be
203 // encountered at this stage.
204 Func->setError("Can't lower unsupported instruction type");
211 Context.advanceCur();
212 Context.advanceNext();
215 // Drives register allocation, allowing all physical registers (except
216 // perhaps for the frame pointer) to be allocated. This set of
217 // registers could potentially be parameterized if we want to restrict
218 // registers e.g. for performance testing.
219 void TargetLowering::regAlloc(RegAllocKind Kind) {
220 TimerMarker T(TimerStack::TT_regAlloc, Func);
221 LinearScan LinearScan(Func);
222 RegSetMask RegInclude = RegSet_None;
223 RegSetMask RegExclude = RegSet_None;
224 RegInclude |= RegSet_CallerSave;
225 RegInclude |= RegSet_CalleeSave;
226 if (hasFramePointer())
227 RegExclude |= RegSet_FramePointer;
228 LinearScan.init(Kind);
229 llvm::SmallBitVector RegMask = getRegisterSet(RegInclude, RegExclude);
230 LinearScan.scan(RegMask, Ctx->getFlags().shouldRandomizeRegAlloc());
233 void TargetLowering::inferTwoAddress() {
234 // Find two-address non-SSA instructions where Dest==Src0, and set
235 // the DestNonKillable flag to keep liveness analysis consistent.
236 for (auto Inst = Context.getCur(), E = Context.getNext(); Inst != E; ++Inst) {
237 if (Inst->isDeleted())
239 if (Variable *Dest = Inst->getDest()) {
240 // TODO(stichnot): We may need to consider all source
241 // operands, not just the first one, if using 3-address
243 if (Inst->getSrcSize() > 0 && Inst->getSrc(0) == Dest)
244 Inst->setDestNonKillable();
249 void TargetLowering::sortVarsByAlignment(VarList &Dest,
250 const VarList &Source) const {
252 // Instead of std::sort, we could do a bucket sort with log2(alignment)
253 // as the buckets, if performance is an issue.
254 std::sort(Dest.begin(), Dest.end(),
255 [this](const Variable *V1, const Variable *V2) {
256 return typeWidthInBytesOnStack(V1->getType()) >
257 typeWidthInBytesOnStack(V2->getType());
261 void TargetLowering::getVarStackSlotParams(
262 VarList &SortedSpilledVariables, llvm::SmallBitVector &RegsUsed,
263 size_t *GlobalsSize, size_t *SpillAreaSizeBytes,
264 uint32_t *SpillAreaAlignmentBytes, uint32_t *LocalsSlotsAlignmentBytes,
265 std::function<bool(Variable *)> TargetVarHook) {
266 const VariablesMetadata *VMetadata = Func->getVMetadata();
267 llvm::BitVector IsVarReferenced(Func->getNumVariables());
268 for (CfgNode *Node : Func->getNodes()) {
269 for (Inst &Inst : Node->getInsts()) {
270 if (Inst.isDeleted())
272 if (const Variable *Var = Inst.getDest())
273 IsVarReferenced[Var->getIndex()] = true;
274 for (SizeT I = 0; I < Inst.getSrcSize(); ++I) {
275 Operand *Src = Inst.getSrc(I);
276 SizeT NumVars = Src->getNumVars();
277 for (SizeT J = 0; J < NumVars; ++J) {
278 const Variable *Var = Src->getVar(J);
279 IsVarReferenced[Var->getIndex()] = true;
285 // If SimpleCoalescing is false, each variable without a register
286 // gets its own unique stack slot, which leads to large stack
287 // frames. If SimpleCoalescing is true, then each "global" variable
288 // without a register gets its own slot, but "local" variable slots
289 // are reused across basic blocks. E.g., if A and B are local to
290 // block 1 and C is local to block 2, then C may share a slot with A or B.
292 // We cannot coalesce stack slots if this function calls a "returns twice"
293 // function. In that case, basic blocks may be revisited, and variables
294 // local to those basic blocks are actually live until after the
295 // called function returns a second time.
296 const bool SimpleCoalescing = !callsReturnsTwice();
298 std::vector<size_t> LocalsSize(Func->getNumNodes());
299 const VarList &Variables = Func->getVariables();
300 VarList SpilledVariables;
301 for (Variable *Var : Variables) {
303 RegsUsed[Var->getRegNum()] = true;
306 // An argument either does not need a stack slot (if passed in a
307 // register) or already has one (if passed on the stack).
310 // An unreferenced variable doesn't need a stack slot.
311 if (!IsVarReferenced[Var->getIndex()])
313 // Check a target-specific variable (it may end up sharing stack slots)
314 // and not need accounting here.
315 if (TargetVarHook(Var))
317 SpilledVariables.push_back(Var);
320 SortedSpilledVariables.reserve(SpilledVariables.size());
321 sortVarsByAlignment(SortedSpilledVariables, SpilledVariables);
323 for (Variable *Var : SortedSpilledVariables) {
324 size_t Increment = typeWidthInBytesOnStack(Var->getType());
325 // We have sorted by alignment, so the first variable we encounter that
326 // is located in each area determines the max alignment for the area.
327 if (!*SpillAreaAlignmentBytes)
328 *SpillAreaAlignmentBytes = Increment;
329 if (SimpleCoalescing && VMetadata->isTracked(Var)) {
330 if (VMetadata->isMultiBlock(Var)) {
331 *GlobalsSize += Increment;
333 SizeT NodeIndex = VMetadata->getLocalUseNode(Var)->getIndex();
334 LocalsSize[NodeIndex] += Increment;
335 if (LocalsSize[NodeIndex] > *SpillAreaSizeBytes)
336 *SpillAreaSizeBytes = LocalsSize[NodeIndex];
337 if (!*LocalsSlotsAlignmentBytes)
338 *LocalsSlotsAlignmentBytes = Increment;
341 *SpillAreaSizeBytes += Increment;
346 void TargetLowering::alignStackSpillAreas(uint32_t SpillAreaStartOffset,
347 uint32_t SpillAreaAlignmentBytes,
349 uint32_t LocalsSlotsAlignmentBytes,
350 uint32_t *SpillAreaPaddingBytes,
351 uint32_t *LocalsSlotsPaddingBytes) {
352 if (SpillAreaAlignmentBytes) {
353 uint32_t PaddingStart = SpillAreaStartOffset;
354 uint32_t SpillAreaStart =
355 Utils::applyAlignment(PaddingStart, SpillAreaAlignmentBytes);
356 *SpillAreaPaddingBytes = SpillAreaStart - PaddingStart;
359 // If there are separate globals and locals areas, make sure the
360 // locals area is aligned by padding the end of the globals area.
361 if (LocalsSlotsAlignmentBytes) {
362 uint32_t GlobalsAndSubsequentPaddingSize = GlobalsSize;
363 GlobalsAndSubsequentPaddingSize =
364 Utils::applyAlignment(GlobalsSize, LocalsSlotsAlignmentBytes);
365 *LocalsSlotsPaddingBytes = GlobalsAndSubsequentPaddingSize - GlobalsSize;
369 void TargetLowering::assignVarStackSlots(VarList &SortedSpilledVariables,
370 size_t SpillAreaPaddingBytes,
371 size_t SpillAreaSizeBytes,
372 size_t GlobalsAndSubsequentPaddingSize,
373 bool UsesFramePointer) {
374 const VariablesMetadata *VMetadata = Func->getVMetadata();
375 size_t GlobalsSpaceUsed = SpillAreaPaddingBytes;
376 size_t NextStackOffset = SpillAreaPaddingBytes;
377 std::vector<size_t> LocalsSize(Func->getNumNodes());
378 const bool SimpleCoalescing = !callsReturnsTwice();
379 for (Variable *Var : SortedSpilledVariables) {
380 size_t Increment = typeWidthInBytesOnStack(Var->getType());
381 if (SimpleCoalescing && VMetadata->isTracked(Var)) {
382 if (VMetadata->isMultiBlock(Var)) {
383 GlobalsSpaceUsed += Increment;
384 NextStackOffset = GlobalsSpaceUsed;
386 SizeT NodeIndex = VMetadata->getLocalUseNode(Var)->getIndex();
387 LocalsSize[NodeIndex] += Increment;
388 NextStackOffset = SpillAreaPaddingBytes +
389 GlobalsAndSubsequentPaddingSize +
390 LocalsSize[NodeIndex];
393 NextStackOffset += Increment;
395 if (UsesFramePointer)
396 Var->setStackOffset(-NextStackOffset);
398 Var->setStackOffset(SpillAreaSizeBytes - NextStackOffset);
402 InstCall *TargetLowering::makeHelperCall(const IceString &Name, Variable *Dest,
404 const bool HasTailCall = false;
405 Constant *CallTarget = Ctx->getConstantExternSym(Name);
407 InstCall::create(Func, MaxSrcs, Dest, CallTarget, HasTailCall);
411 void TargetLowering::emitWithoutPrefix(const ConstantRelocatable *C) const {
414 Ostream &Str = Ctx->getStrEmit();
415 if (C->getSuppressMangling())
418 Str << Ctx->mangleName(C->getName());
419 RelocOffsetT Offset = C->getOffset();
427 void TargetLowering::emit(const ConstantRelocatable *C) const {
430 Ostream &Str = Ctx->getStrEmit();
431 Str << getConstantPrefix();
432 emitWithoutPrefix(C);
435 std::unique_ptr<TargetDataLowering>
436 TargetDataLowering::createLowering(GlobalContext *Ctx) {
437 TargetArch Target = Ctx->getFlags().getTargetArch();
438 #define SUBZERO_TARGET(X) \
439 if (Target == Target_##X) \
440 return std::unique_ptr<TargetDataLowering>(TargetData##X::create(Ctx));
441 #include "llvm/Config/SZTargets.def"
443 llvm_unreachable("Unsupported target data lowering");
447 TargetDataLowering::~TargetDataLowering() {}
449 } // end of namespace Ice