I think this pass was previously used under the assumption that most functions would not need a frame pointer and it would be more efficient to store the old stack pointer in a regular register pair. Unfortunately, right now we're forced to always reserve the Y register as a frame pointer: whether or not this is needed is only known after regsiter allocation at which point it doesn't make sense anymore to mark it as non-reserved. Therefore, it makes sense to use the Y register to store the old stack pointer in functions with dynamic allocas (with a variable size or not in the entry block). Knowing this can make the code around dynamic allocas a lot simpler: simply save/restore the frame pointer. This is especially relevant in functions that have a frame pointer anyway (for example, because they have stack spills). The stack restore in the epilogue will implicitly restore the old stack pointer, so there is no need to store the old stack pointer separately. It even reduces register pressure as a side effect. Differential Revision: https://reviews.llvm.org/D97815
131 lines
4.0 KiB
C++
131 lines
4.0 KiB
C++
//===-- AVRTargetMachine.cpp - Define TargetMachine for AVR ---------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the AVR specific subclass of TargetMachine.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "AVRTargetMachine.h"
|
|
|
|
#include "llvm/CodeGen/Passes.h"
|
|
#include "llvm/CodeGen/TargetPassConfig.h"
|
|
#include "llvm/IR/LegacyPassManager.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/MC/TargetRegistry.h"
|
|
|
|
#include "AVR.h"
|
|
#include "AVRTargetObjectFile.h"
|
|
#include "MCTargetDesc/AVRMCTargetDesc.h"
|
|
#include "TargetInfo/AVRTargetInfo.h"
|
|
|
|
namespace llvm {
|
|
|
|
static const char *AVRDataLayout =
|
|
"e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8";
|
|
|
|
/// Processes a CPU name.
|
|
static StringRef getCPU(StringRef CPU) {
|
|
if (CPU.empty() || CPU == "generic") {
|
|
return "avr2";
|
|
}
|
|
|
|
return CPU;
|
|
}
|
|
|
|
static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) {
|
|
return RM.getValueOr(Reloc::Static);
|
|
}
|
|
|
|
AVRTargetMachine::AVRTargetMachine(const Target &T, const Triple &TT,
|
|
StringRef CPU, StringRef FS,
|
|
const TargetOptions &Options,
|
|
Optional<Reloc::Model> RM,
|
|
Optional<CodeModel::Model> CM,
|
|
CodeGenOpt::Level OL, bool JIT)
|
|
: LLVMTargetMachine(T, AVRDataLayout, TT, getCPU(CPU), FS, Options,
|
|
getEffectiveRelocModel(RM),
|
|
getEffectiveCodeModel(CM, CodeModel::Small), OL),
|
|
SubTarget(TT, std::string(getCPU(CPU)), std::string(FS), *this) {
|
|
this->TLOF = std::make_unique<AVRTargetObjectFile>();
|
|
initAsmInfo();
|
|
}
|
|
|
|
namespace {
|
|
/// AVR Code Generator Pass Configuration Options.
|
|
class AVRPassConfig : public TargetPassConfig {
|
|
public:
|
|
AVRPassConfig(AVRTargetMachine &TM, PassManagerBase &PM)
|
|
: TargetPassConfig(TM, PM) {}
|
|
|
|
AVRTargetMachine &getAVRTargetMachine() const {
|
|
return getTM<AVRTargetMachine>();
|
|
}
|
|
|
|
void addIRPasses() override;
|
|
bool addInstSelector() override;
|
|
void addPreSched2() override;
|
|
void addPreEmitPass() override;
|
|
};
|
|
} // namespace
|
|
|
|
TargetPassConfig *AVRTargetMachine::createPassConfig(PassManagerBase &PM) {
|
|
return new AVRPassConfig(*this, PM);
|
|
}
|
|
|
|
void AVRPassConfig::addIRPasses() {
|
|
// Expand instructions like
|
|
// %result = shl i32 %n, %amount
|
|
// to a loop so that library calls are avoided.
|
|
addPass(createAVRShiftExpandPass());
|
|
|
|
TargetPassConfig::addIRPasses();
|
|
}
|
|
|
|
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAVRTarget() {
|
|
// Register the target.
|
|
RegisterTargetMachine<AVRTargetMachine> X(getTheAVRTarget());
|
|
|
|
auto &PR = *PassRegistry::getPassRegistry();
|
|
initializeAVRExpandPseudoPass(PR);
|
|
initializeAVRRelaxMemPass(PR);
|
|
initializeAVRShiftExpandPass(PR);
|
|
}
|
|
|
|
const AVRSubtarget *AVRTargetMachine::getSubtargetImpl() const {
|
|
return &SubTarget;
|
|
}
|
|
|
|
const AVRSubtarget *AVRTargetMachine::getSubtargetImpl(const Function &) const {
|
|
return &SubTarget;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Pass Pipeline Configuration
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
bool AVRPassConfig::addInstSelector() {
|
|
// Install an instruction selector.
|
|
addPass(createAVRISelDag(getAVRTargetMachine(), getOptLevel()));
|
|
// Create the frame analyzer pass used by the PEI pass.
|
|
addPass(createAVRFrameAnalyzerPass());
|
|
|
|
return false;
|
|
}
|
|
|
|
void AVRPassConfig::addPreSched2() {
|
|
addPass(createAVRRelaxMemPass());
|
|
addPass(createAVRExpandPseudoPass());
|
|
}
|
|
|
|
void AVRPassConfig::addPreEmitPass() {
|
|
// Must run branch selection immediately preceding the asm printer.
|
|
addPass(&BranchRelaxationPassID);
|
|
}
|
|
|
|
} // end of namespace llvm
|