#ifdef ART_ENABLE_CODEGEN_arm // Special ARM code generator for codegen testing in a limited code // generation environment (i.e. with no runtime support). // // Note: If we want to exercise certains HIR constructions // (e.g. reference field load in Baker read barrier configuration) in // codegen tests in the future, we should also: // - save the Thread Register (R9) and possibly the Marking Register // (R8) before entering the generated function (both registers are // callee-save in AAPCS); // - set these registers to meaningful values before or upon entering // the generated function (so that generated code using them is // correct); // - restore their original values before leaving the generated // function.
// Provide our own codegen, that ensures the C calling conventions // are preserved. Currently, ART and C do not match as R4 is caller-save // in ART, and callee-save in C. Alternatively, we could use or write // the stub that saves and restores all registers, but it is easier // to just overwrite the code generator. class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL { public:
TestCodeGeneratorARMVIXL(HGraph* graph, const CompilerOptions& compiler_options)
: arm::CodeGeneratorARMVIXL(graph, compiler_options) {
AddAllocatedCoreRegister(arm::R6);
AddAllocatedCoreRegister(arm::R7);
blocked_registers_.AddCoreRegisterSet((1u << arm::R4) | (1u << arm::R6) | (1u << arm::R7));
}
void MaybeGenerateMarkingRegisterCheck([[maybe_unused]] int code,
[[maybe_unused]] Location temp_loc) override { // When turned on, the marking register checks in // CodeGeneratorARMVIXL::MaybeGenerateMarkingRegisterCheck expects the // Thread Register and the Marking Register to be set to // meaningful values. This is not the case in codegen testing, so // just disable them entirely here (by doing nothing in this // method).
}
}; #endif
#ifdef ART_ENABLE_CODEGEN_arm64 // Special ARM64 code generator for codegen testing in a limited code // generation environment (i.e. with no runtime support). // // Note: If we want to exercise certains HIR constructions // (e.g. reference field load in Baker read barrier configuration) in // codegen tests in the future, we should also: // - save the Thread Register (X19) and possibly the Marking Register // (X20) before entering the generated function (both registers are // callee-save in AAPCS64); // - set these registers to meaningful values before or upon entering // the generated function (so that generated code using them is // correct); // - restore their original values before leaving the generated // function. class TestCodeGeneratorARM64 : public arm64::CodeGeneratorARM64 { public:
TestCodeGeneratorARM64(HGraph* graph, const CompilerOptions& compiler_options)
: arm64::CodeGeneratorARM64(graph, compiler_options) {}
void MaybeGenerateMarkingRegisterCheck([[maybe_unused]] int codem,
[[maybe_unused]] Location temp_loc) override { // When turned on, the marking register checks in // CodeGeneratorARM64::MaybeGenerateMarkingRegisterCheck expect the // Thread Register and the Marking Register to be set to // meaningful values. This is not the case in codegen testing, so // just disable them entirely here (by doing nothing in this // method).
}
}; #endif
#ifdef ART_ENABLE_CODEGEN_x86 class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 { public:
TestCodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options)
: x86::CodeGeneratorX86(graph, compiler_options) { // Save edi, we need it for getting enough registers for long multiplication.
AddAllocatedCoreRegister(x86::EDI); // Block EBX because it's a callee-save register in C, but caller-save for ART. // Make EDI available.
RegisterSet blocked_registers = RegisterSet::Empty();
blocked_registers.AddCoreRegisterSet(
(blocked_registers_.GetCoreRegisterSet() | (1u << x86::EBX)) & ~(1u << x86::EDI));
blocked_registers.AddFpuRegisterSet(blocked_registers_.GetFpuRegisterSet());
blocked_registers_ = blocked_registers;
}
}; #endif
// Check that the current runtime ISA matches the target ISA. staticbool DoesHardwareSupportISA(InstructionSet target_isa) { return (target_isa == kRuntimeISA) // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2).
|| (kRuntimeISA == InstructionSet::kArm && target_isa == InstructionSet::kThumb2);
}
// Check that the current runtime ISA matches the target ISA and the ISA features requested are // available on the hardware. staticbool CanExecuteOnHardware(const CodeGenerator& codegen) { const InstructionSetFeatures* isa_features =
codegen.GetCompilerOptions().GetInstructionSetFeatures(); return DoesHardwareSupportISA(codegen.GetInstructionSet())
&& InstructionSetFeatures::FromHwcap()->HasAtLeast(isa_features);
}
template <typename Expected> staticvoid VerifyGeneratedCode(const CodeGenerator& codegen,
Expected (*f)(), bool has_result,
Expected expected) {
ASSERT_TRUE(CanExecute(codegen)) << "Target isa is not executable.";
// Verify on simulator.
InstructionSet target_isa = codegen.GetInstructionSet(); if (BasicCodeSimulator::CanSimulate(target_isa)) { // Use basic simulator: for the gtests we don't have runtime started, so won't have entrypoints // initialized.
std::unique_ptr<BasicCodeSimulator> simulator(
CreateBasicCodeSimulator(codegen.GetInstructionSet(), kDefaultStackSize));
Expected result = SimulatorExecute<Expected>(simulator.get(), f);
if (has_result) {
ASSERT_EQ(expected, result);
}
}
// Verify on hardware. if (CanExecuteOnHardware(codegen)) {
Expected result = f(); if (has_result) {
ASSERT_EQ(expected, result);
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.