Skip to content

Commit

Permalink
[snippy] Replace hardcoded RAM/ROM to list of memory regions
Browse files Browse the repository at this point in the history
  • Loading branch information
dybv-sc authored and asi-sc committed Dec 26, 2024
1 parent 3d7e2f8 commit a5ff3e7
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 208 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ sections:
ACCESS: rw
- no: 3
VMA: 0x80000000
SIZE: 0x400000
SIZE: 0x10c8
LMA: 0x80000000
ACCESS: rw

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ sections:
ACCESS: rw
- no: 3
VMA: 0x80000000
SIZE: 0x400000
SIZE: 0x10c8
LMA: 0x80000000
ACCESS: rw

Expand Down
13 changes: 2 additions & 11 deletions llvm/tools/llvm-snippy/include/snippy/Generator/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,24 +95,15 @@ class Interpreter final {

void initTransactionMechanism();
void dumpOneRange(NamedMemoryRange Range, raw_fd_ostream &OS) const;
bool coveredByMemoryRegion(MemAddr Start, MemAddr Size) const;

public:
uint64_t getProgEnd() const { return ProgEnd; }
uint64_t getRomStart() const { return Env.SimCfg.RomStart; }
uint64_t getRamStart() const { return Env.SimCfg.RamStart; }

uint64_t getRomSize() const { return Env.SimCfg.RomSize; }
uint64_t getRamSize() const { return Env.SimCfg.RamSize; }

uint64_t getRomEnd() const { return getRomStart() + getRomSize(); }
uint64_t getRamEnd() const { return getRamStart() + getRamSize(); }

bool endOfProg() const;

static SimulationEnvironment createSimulationEnvironment(
SnippyProgramContext &SPC, const TargetSubtargetInfo &ST,
const GeneratorSettings &Settings, const MemoryConfig &MemCfg,
TargetGenContextInterface &TgtCtx);
const GeneratorSettings &Settings, TargetGenContextInterface &TgtCtx);

static std::unique_ptr<SimulatorInterface> createSimulatorForTarget(
const SnippyTarget &TGT, const TargetSubtargetInfo &Subtarget,
Expand Down
17 changes: 3 additions & 14 deletions llvm/tools/llvm-snippy/include/snippy/Generator/SimRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,9 @@ class SimRunner {

// Preform co-simulation run.
// Each interpreter state will be reset before run.
void run(StringRef Programm, const IRegisterState &InitialRegState,
ProgramCounterType StartPC);

// Adds output section name to the sim config
// in order to load it later to the model before execution.
void addNewEnvSection(const std::string &NewSectOutputName) {
auto &AdditionalSectionsNames = Env->SimCfg.AdditionalSectionsNames;
if (std::count(AdditionalSectionsNames.begin(),
AdditionalSectionsNames.end(), NewSectOutputName) != 0)
snippy::fatal(formatv("Section {0} has already been added to sim env.",
NewSectOutputName));
AdditionalSectionsNames.push_back(NewSectOutputName);
}

void run(const IRegisterState &InitialRegState, ProgramCounterType StartPC);
// Loads image of program into each interpreter.
void loadElf(StringRef Image);
auto &getSimConfig() & {
assert(Env);
return Env->SimCfg;
Expand Down
20 changes: 7 additions & 13 deletions llvm/tools/llvm-snippy/include/snippy/Simulator/Simulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,7 @@ struct SimulationConfig {
ProgramCounterType Size = 0;
std::string Name;
};
std::vector<Section> ProgSections;

ProgramCounterType RomStart = 0;
ProgramCounterType RomSize = 0;
std::string RomSectionName;

// Additional sections are the sections that need to be loaded in model
// e.g. RW sections filled with constants should be loaded to the model
// (these are mangled names)
std::vector<std::string> AdditionalSectionsNames;

ProgramCounterType RamStart = 0;
ProgramCounterType RamSize = 0;
std::vector<Section> MemoryRegions;

std::string TraceLogPath;
};
Expand Down Expand Up @@ -130,4 +118,10 @@ template <> struct yaml::MappingTraits<snippy::SimulationConfig> {
static void mapping(yaml::IO &IO, snippy::SimulationConfig &Cfg);
};

template <> struct yaml::MappingTraits<snippy::SimulationConfig::Section> {
static void mapping(yaml::IO &IO, snippy::SimulationConfig::Section &S);
};
} // namespace llvm

LLVM_SNIPPY_YAML_IS_SEQUENCE_ELEMENT(llvm::snippy::SimulationConfig::Section,
/* flow */ false);
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ enum class WarningName {
TooFarMaxPCDist,
ModelException,
UnusedSection,
EmptyElfSection,
GenPlanVerification,
SeedNotSpecified,
};
Expand Down
162 changes: 63 additions & 99 deletions llvm/tools/llvm-snippy/lib/Generator/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,55 +70,21 @@ static std::unique_ptr<object::ObjectFile> makeObjectFile(MemoryBufferRef Buf) {
return std::move(Exp.get());
}

static auto getSectionIt(object::ObjectFile &Obj, StringRef SectionName) {
auto SecIt = std::find_if(Obj.section_begin(), Obj.section_end(),
[&SectionName](const auto &S) {
auto Exp = S.getName();
if (!Exp)
return false;
return Exp.get() == SectionName;
});
return SecIt;
}

static bool hasSection(object::ObjectFile &Obj, StringRef SectionName) {
return getSectionIt(Obj, SectionName) != Obj.section_end();
}

static StringRef getSectionData(object::ObjectFile &Obj,
StringRef SectionName) {
auto SectionIt = getSectionIt(Obj, SectionName);
assert(SectionIt != Obj.section_end());

auto Exp = SectionIt->getContents();
if (!Exp)
snippy::fatal(SectionName + " section is empty");
return Exp.get();
}

static auto getSectionLA(object::ObjectFile &Obj, StringRef SectionName) {
auto SectionIt = getSectionIt(Obj, SectionName);
assert(SectionIt != Obj.section_end());
return SectionIt->getAddress();
}

} // namespace llvm

namespace llvm {
namespace snippy {

namespace {
void applyMemCfgToSimCfg(const MemoryConfig &MemCfg, SimulationConfig &SimCfg) {
llvm::transform(MemCfg.ProgSections, std::back_inserter(SimCfg.ProgSections),
[](auto &Section) {
return SimulationConfig::Section{
Section.Start, Section.Size, Section.Name};
void applyMemCfgToSimCfg(const Linker &L, SimulationEnvironment &Env) {
llvm::transform(L.sections(), std::back_inserter(Env.SimCfg.MemoryRegions),
[](auto &SE) {
auto &OutS = SE.OutputSection;
return SimulationConfig::Section{OutS.Desc.VMA,
OutS.Desc.Size, OutS.Name};
});
SimCfg.RomStart = MemCfg.Rom.Start;
SimCfg.RomSize = MemCfg.Rom.Size;
SimCfg.RomSectionName = MemCfg.Rom.Name;
SimCfg.RamStart = MemCfg.Ram.Start;
SimCfg.RamSize = MemCfg.Ram.Size;
llvm::transform(L.sections(), std::back_inserter(Env.Sections),
[](auto &SE) { return SE.OutputSection.Desc; });
}
} // namespace

Expand Down Expand Up @@ -178,8 +144,7 @@ static void writeSectionToFile(ArrayRef<char> Data,

SimulationEnvironment Interpreter::createSimulationEnvironment(
SnippyProgramContext &SPC, const TargetSubtargetInfo &ST,
const GeneratorSettings &Settings, const MemoryConfig &MemCfg,
TargetGenContextInterface &TgtCtx) {
const GeneratorSettings &Settings, TargetGenContextInterface &TgtCtx) {
auto &State = SPC.getLLVMState();
const auto &SnippyTGT = State.getSnippyTarget();

Expand All @@ -190,10 +155,7 @@ SimulationEnvironment Interpreter::createSimulationEnvironment(
Env.SnippyTGT = &SnippyTGT;
Env.ST = &ST;

applyMemCfgToSimCfg(MemCfg, Env.SimCfg);
std::transform(L.sections().begin(), L.sections().end(),
std::back_inserter(Env.Sections),
[](auto &SE) { return SE.OutputSection.Desc; });
applyMemCfgToSimCfg(L, Env);

Env.SimCfg.TraceLogPath = TraceLogPath.getValue();
Env.TgtGenCtx = &TgtCtx;
Expand Down Expand Up @@ -230,14 +192,14 @@ bool Interpreter::compareStates(const Interpreter &Another,
if (!CheckMemory)
return true;

std::vector<char> MI1, MI2;

MI1.resize(getRamSize());
MI2.resize(getRamSize());

Simulator->readMem(getRamStart(), MI1);
Another.Simulator->readMem(getRamStart(), MI2);
return MI1 == MI2;
return llvm::all_of(Env.SimCfg.MemoryRegions, [&](auto &Region) {
std::vector<char> MI1, MI2;
MI1.resize(Region.Size);
MI2.resize(Region.Size);
Simulator->readMem(Region.Start, MI1);
Another.Simulator->readMem(Region.Start, MI2);
return MI1 == MI2;
});
}

bool Interpreter::endOfProg() const {
Expand All @@ -246,14 +208,10 @@ bool Interpreter::endOfProg() const {

void Interpreter::resetMem() {
const auto &SimCfg = Env.SimCfg;
std::vector<char> RAMZeroMem(SimCfg.RamSize, 0);
std::vector<char> ROMZeroMem(SimCfg.RomSize, 0);

Simulator->writeMem(SimCfg.RamStart, RAMZeroMem);
Simulator->writeMem(SimCfg.RomStart, ROMZeroMem);
for (auto &Section : SimCfg.ProgSections) {
std::vector<char> ProgZeroMem(Section.Size, 0);
Simulator->writeMem(Section.Start, ProgZeroMem);
std::vector<char> Zeros;
for (auto &&Region : SimCfg.MemoryRegions) {
Zeros.resize(Region.Size, 0);
Simulator->writeMem(Region.Start, Zeros);
}
}

Expand Down Expand Up @@ -290,12 +248,51 @@ void Interpreter::reportSimulationFatalError(StringRef PrefixMessage) const {

snippy::fatal(ErrorMessage.c_str());
}
bool Interpreter::coveredByMemoryRegion(MemAddr Start, MemAddr Size) const {
auto IsInsideOf = [&](auto &&Reg) {
return Reg.Start <= Start && Reg.Start + Reg.Size >= Start + Size;
};
return llvm::any_of(Env.SimCfg.MemoryRegions, IsInsideOf);
}

static StringRef getSectionName(llvm::object::SectionRef S) {
if (auto EName = S.getName())
return *EName;
else
return "";
}

void Interpreter::loadElfImage(StringRef ElfImage) {
std::string ProgramText;
auto MemBuff = MemoryBuffer::getMemBuffer(ElfImage, "", false);
auto ObjectFile = makeObjectFile(*MemBuff);

// FIXME: we need to provide more context to error message.
// (at least elf name)
if (ObjectFile->isRelocatableObject())
snippy::fatal("Trying to load relocatable object into model");
for (auto &&Section : ObjectFile->sections()) {
if (!Section.isText() && !Section.isData() && !Section.isBSS())
continue;
auto Address = Section.getAddress();
auto Size = Section.getSize();
if (!coveredByMemoryRegion(Address, Size))
snippy::fatal(
formatv("Trying to load/allocate section '{0}' at address 0x{1:x} of "
"size 0x{2:x} which is not covered by model memory region",
getSectionName(Section), Address, Size));
if (Section.isText() || Section.isData()) {
if (auto EContents = Section.getContents())
Simulator->writeMem(Address, *EContents);
else
snippy::warn(
WarningName::EmptyElfSection,
formatv("ignored LOAD section '{0}'", getSectionName(Section)),
"empty contents");
} else if (Section.isBSS()) {
std::vector<char> Zeroes(Size, 0);
Simulator->writeMem(Address, Zeroes);
}
}
auto EndOfProgSym = llvm::find_if(ObjectFile->symbols(), [](auto &Sym) {
auto EName = Sym.getName();
return EName && EName.get() == Linker::getExitSymbolName();
Expand All @@ -306,34 +303,6 @@ void Interpreter::loadElfImage(StringRef ElfImage) {
auto EAddress = EndOfProgSym->getAddress();
assert(EAddress && "Expected the address of symbol to be known");
ProgEnd = EAddress.get();

for (auto &ProgSection : Env.SimCfg.ProgSections) {
assert(hasSection(*ObjectFile, ProgSection.Name));

ProgramText = getSectionData(*ObjectFile, ProgSection.Name);

if (ProgSection.Size < ProgramText.size())
snippy::fatal(formatv("RX section '{0}' failed to fit code mapped to it: "
"section size is {1} and code size is {2}",
ProgSection.Name, ProgSection.Size,
ProgramText.size()));
Simulator->writeMem(ProgSection.Start, ProgramText);
}
if (!Env.SimCfg.RomSectionName.empty()) {
auto RODataName = Env.SimCfg.RomSectionName;
// Elf image might not have this section if
// .rodata happens to be empty.
if (hasSection(*ObjectFile, RODataName)) {
auto SnippyData = getSectionData(*ObjectFile, RODataName);
Simulator->writeMem(getSectionLA(*ObjectFile, RODataName), SnippyData);
}
}

// adding sections with non-zero data
for (auto &It : Env.SimCfg.AdditionalSectionsNames) {
auto Data = getSectionData(*ObjectFile, It);
Simulator->writeMem(getSectionLA(*ObjectFile, It), Data);
}
}

void Interpreter::addInstr(const MachineInstr &MI, const LLVMState &State) {
Expand Down Expand Up @@ -424,12 +393,7 @@ void Interpreter::initTransactionMechanism() {
Env.CallbackHandler->getObserverByHandle(*TransactionsObserverHandle);
assert(Transactions.empty());

SmallVector<std::pair<uint64_t, uint64_t>, 3> MemoryConfig = {
std::pair{getRomStart(), getRomSize()},
std::pair{getRamStart(), getRamSize()}};
for (auto &Section : Env.SimCfg.ProgSections)
MemoryConfig.emplace_back(std::make_pair(Section.Start, Section.Size));
for (auto [Start, Size] : MemoryConfig) {
for (auto [Start, Size, _] : Env.SimCfg.MemoryRegions) {
if (Size == 0)
continue;
std::vector<char> Snapshot(Size);
Expand Down
43 changes: 7 additions & 36 deletions llvm/tools/llvm-snippy/lib/Generator/SimRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,6 @@

namespace llvm {
namespace snippy {
namespace {
Expected<uint64_t> getAddressOfSymbolInImage(StringRef Image,
StringRef SymbolName) {
auto MemBuf = MemoryBuffer::getMemBuffer(Image, "", false);

auto &&Bin = object::ObjectFile::createObjectFile(*MemBuf);
if (!Bin)
return Bin.takeError();
auto &&Obj = *Bin;

auto ExitSimIt = std::find_if(Obj->symbols().begin(), Obj->symbols().end(),
[SymbolName](const auto &Sym) {
if (auto Name = Sym.getName())
return *Name == SymbolName;
return false;
});
if (ExitSimIt == Obj->symbols().end())
return {make_error<Failure>(Twine("no symbol ") + Twine(SymbolName) +
Twine(" in image"))};

auto ExpectedAddress = ExitSimIt->getAddress();
if (!ExpectedAddress)
return ExpectedAddress.takeError();

return *ExpectedAddress;
}
} // namespace

SimRunner::SimRunner(LLVMContext &Ctx, const SnippyTarget &TGT,
const TargetSubtargetInfo &Subtarget,
Expand All @@ -61,18 +34,16 @@ SimRunner::SimRunner(LLVMContext &Ctx, const SnippyTarget &TGT,
}
}

void SimRunner::run(StringRef Program, const IRegisterState &InitialRegState,
void SimRunner::loadElf(StringRef Image) {
for (auto &I : CoInterp)
I->loadElfImage(Image);
}
void SimRunner::run(const IRegisterState &InitialRegState,
ProgramCounterType StartPC) {
auto StopPC = getAddressOfSymbolInImage(Program, Linker::getExitSymbolName());
if (auto E = StopPC.takeError()) {
auto Err = toString(std::move(E));
snippy::fatal("[Internal error]: unable to get last instruction PC: " +
Twine(Err) + Twine("\nPlease, report a bug"));
}

for (auto &I : CoInterp) {
I->setInitialState(InitialRegState);
I->loadElfImage(Program);
I->setStopModeByPC(*StopPC);
I->setStopModeByPC(I->getProgEnd());
I->setPC(StartPC);
}

Expand Down
Loading

0 comments on commit a5ff3e7

Please sign in to comment.