Index: lib/Target/Sparc/CMakeLists.txt =================================================================== --- lib/Target/Sparc/CMakeLists.txt +++ lib/Target/Sparc/CMakeLists.txt @@ -13,6 +13,7 @@ add_llvm_target(SparcCodeGen DelaySlotFiller.cpp + LeonPasses.cpp SparcAsmPrinter.cpp SparcInstrInfo.cpp SparcISelDAGToDAG.cpp Index: lib/Target/Sparc/LeonFeatures.td =================================================================== --- lib/Target/Sparc/LeonFeatures.td +++ lib/Target/Sparc/LeonFeatures.td @@ -36,4 +36,10 @@ "true", "Enable CASA instruction for LEON3 and LEON4 processors" >; - \ No newline at end of file + +def InsertNOPLoad: SubtargetFeature< + "insertnopload", + "InsertNOPLoad", + "true", + "LEON3 erratum fix: Insert a NOP instruction after every single-cycle load instruction when the next instruction is another load/store instruction" +>; Index: lib/Target/Sparc/LeonPasses.h =================================================================== --- lib/Target/Sparc/LeonPasses.h +++ lib/Target/Sparc/LeonPasses.h @@ -0,0 +1,46 @@ +//===------- LeonPasses.h - Define passes specific to LEON ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SPARC_LEON_PASSES_H +#define LLVM_LIB_TARGET_SPARC_LEON_PASSES_H + +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineBasicBlock.h" + +#include "Sparc.h" +#include "SparcSubtarget.h" + +using namespace llvm; + +class LEONMachineFunctionPass : public MachineFunctionPass { +protected: + const SparcSubtarget *Subtarget; + +protected: + LEONMachineFunctionPass(TargetMachine &tm, char& ID); + LEONMachineFunctionPass(char& ID); +}; + +class InsertNOPLoad : public LEONMachineFunctionPass { +public: + static char ID; + + InsertNOPLoad(TargetMachine &tm); + bool runOnMachineFunction(MachineFunction& MF) override; + + const char *getPassName() const override { + return "InsertNOPLoad: LEON Erratum fix - Insert a NOP instruction after every single-cycle load instruction when the next instruction is another load/store instruction"; + } +}; + +#endif Index: lib/Target/Sparc/LeonPasses.cpp =================================================================== --- lib/Target/Sparc/LeonPasses.cpp +++ lib/Target/Sparc/LeonPasses.cpp @@ -0,0 +1,79 @@ +//===------ LeonPasses.cpp - Define passes specific to LEON ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#include "LeonPasses.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/ISDOpcodes.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +LEONMachineFunctionPass::LEONMachineFunctionPass(TargetMachine &tm, char& ID) : + MachineFunctionPass(ID) +{ +} + +LEONMachineFunctionPass::LEONMachineFunctionPass(char& ID) : + MachineFunctionPass(ID) +{ +} + +//***************************************************************************** +//**** InsertNOPLoad pass +//***************************************************************************** +//This pass inserts a NOP after any LD or LDF instruction. +// +char InsertNOPLoad::ID = 0; + +InsertNOPLoad::InsertNOPLoad(TargetMachine &tm) : + LEONMachineFunctionPass(tm, ID) +{ +} + +bool InsertNOPLoad::runOnMachineFunction(MachineFunction& MF) +{ + Subtarget = &MF.getSubtarget(); + const TargetInstrInfo& TII = *Subtarget->getInstrInfo(); + DebugLoc DL = DebugLoc(); + + bool Modified = false; + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++ MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) { + //errs() << "Inserting NOP after LD instruction\n"; + MachineBasicBlock::iterator NMBBI = std::next(MBBI); + BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); + Modified = true; + } + else if (MI.isInlineAsm()) { + std::string AsmString (MI.getOperand(InlineAsm::MIOp_AsmString) + .getSymbolName()); + std::string LDOpCoode ("ld"); + std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(), + ::tolower); + if (AsmString.find(LDOpCoode) == 0) { // an inline ld or ldf instruction + //errs() << "Inserting NOP after LD instruction\n"; + MachineBasicBlock::iterator NMBBI = std::next(MBBI); + BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); + Modified = true; + } + } + } + } + + return Modified; +} Index: lib/Target/Sparc/Sparc.td =================================================================== --- lib/Target/Sparc/Sparc.td +++ lib/Target/Sparc/Sparc.td @@ -107,12 +107,12 @@ // LEON 2 FT (AT697E) // TO DO: Place-holder: Processor specific features will be added *very* soon here. def : Processor<"at697e", LEON2Itineraries, - [FeatureLeon]>; + [FeatureLeon, InsertNOPLoad]>; // LEON 2 FT (AT697F) // TO DO: Place-holder: Processor specific features will be added *very* soon here. def : Processor<"at697f", LEON2Itineraries, - [FeatureLeon]>; + [FeatureLeon, InsertNOPLoad]>; // LEON 3 FT generic @@ -122,12 +122,12 @@ // LEON 3 FT (UT699). Provides features for the UT699 processor // - covers all the erratum fixes for LEON3, but does not support the CASA instruction. def : Processor<"ut699", LEON3Itineraries, - [FeatureLeon, UMACSMACSupport]>; + [FeatureLeon, InsertNOPLoad]>; // LEON3 FT (GR712RC). Provides features for the GR712RC processor. // - covers all the erratum fixed for LEON3 and support for the CASA instruction. def : Processor<"gr712rc", LEON3Itineraries, - [FeatureLeon, UMACSMACSupport, LeonCASA]>; + [FeatureLeon, LeonCASA]>; // LEON 4 FT generic def : Processor<"leon4", LEON4Itineraries, Index: lib/Target/Sparc/SparcISelLowering.h =================================================================== --- lib/Target/Sparc/SparcISelLowering.h +++ lib/Target/Sparc/SparcISelLowering.h @@ -85,6 +85,14 @@ std::string &Constraint, std::vector &Ops, SelectionDAG &DAG) const override; + + unsigned + getInlineAsmMemConstraint(StringRef ConstraintCode) const override { + if (ConstraintCode == "o") + return InlineAsm::Constraint_o; + return TargetLowering::getInlineAsmMemConstraint(ConstraintCode); + } + std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const override; Index: lib/Target/Sparc/SparcSubtarget.h =================================================================== --- lib/Target/Sparc/SparcSubtarget.h +++ lib/Target/Sparc/SparcSubtarget.h @@ -44,6 +44,7 @@ // LEON features bool HasUmacSmac; bool HasLeonCasa; + bool InsertNOPLoad; SparcInstrInfo InstrInfo; SparcTargetLowering TLInfo; @@ -83,6 +84,7 @@ // Leon options bool hasUmacSmac() const { return HasUmacSmac; } bool hasLeonCasa() const { return HasLeonCasa; } + bool insertNOPLoad() const { return InsertNOPLoad; } /// ParseSubtargetFeatures - Parses features string setting specified /// subtarget options. Definition of function is auto generated by tblgen. Index: lib/Target/Sparc/SparcSubtarget.cpp =================================================================== --- lib/Target/Sparc/SparcSubtarget.cpp +++ lib/Target/Sparc/SparcSubtarget.cpp @@ -39,6 +39,7 @@ // Leon features HasLeonCasa = false; HasUmacSmac = false; + InsertNOPLoad = false; // Determine default and user specified characteristics std::string CPUName = CPU; Index: lib/Target/Sparc/SparcTargetMachine.h =================================================================== --- lib/Target/Sparc/SparcTargetMachine.h +++ lib/Target/Sparc/SparcTargetMachine.h @@ -22,6 +22,7 @@ class SparcTargetMachine : public LLVMTargetMachine { std::unique_ptr TLOF; + SparcSubtarget Subtarget; bool is64Bit; mutable StringMap> SubtargetMap; public: @@ -31,6 +32,7 @@ CodeGenOpt::Level OL, bool is64bit); ~SparcTargetMachine() override; + const SparcSubtarget *getSubtargetImpl() const { return &Subtarget; } const SparcSubtarget *getSubtargetImpl(const Function &) const override; // Pass Pipeline Configuration Index: lib/Target/Sparc/SparcTargetMachine.cpp =================================================================== --- lib/Target/Sparc/SparcTargetMachine.cpp +++ lib/Target/Sparc/SparcTargetMachine.cpp @@ -13,6 +13,7 @@ #include "SparcTargetMachine.h" #include "SparcTargetObjectFile.h" #include "Sparc.h" +#include "LeonPasses.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/LegacyPassManager.h" @@ -69,9 +70,9 @@ CodeGenOpt::Level OL, bool is64bit) : LLVMTargetMachine(T, computeDataLayout(TT, is64bit), TT, CPU, FS, Options, getEffectiveRelocModel(RM), CM, OL), - TLOF(make_unique()) { + TLOF(make_unique()), + Subtarget(TT, CPU, FS, *this, is64bit), is64Bit(is64bit) { initAsmInfo(); - this->is64Bit = is64bit; } SparcTargetMachine::~SparcTargetMachine() {} @@ -144,6 +145,11 @@ void SparcPassConfig::addPreEmitPass(){ addPass(createSparcDelaySlotFillerPass(getSparcTargetMachine())); + + if (this->getSparcTargetMachine().getSubtargetImpl()->insertNOPLoad()) + { + addPass(new InsertNOPLoad(getSparcTargetMachine())); + } } void SparcV8TargetMachine::anchor() { } Index: test/CodeGen/SPARC/LeonInsertNOPLoadPassUT.ll =================================================================== --- test/CodeGen/SPARC/LeonInsertNOPLoadPassUT.ll +++ test/CodeGen/SPARC/LeonInsertNOPLoadPassUT.ll @@ -0,0 +1,43 @@ +; RUN: llc %s -O0 -march=sparc -mcpu=ut699 -o - | FileCheck %s +; RUN: llc %s -O0 -march=sparc -mcpu=leon3 -mattr=+insertnopload -o - | FileCheck %s + +; CHECK-LABEL: ld_float_test +; CHECK: ld [%o0+%lo(.LCPI0_0)], %f0 +; CHECK-NEXT: nop +define float @ld_float_test() #0 { +entry: + %f = alloca float, align 4 + store float 0x3FF3C08320000000, float* %f, align 4 + %0 = load float, float* %f, align 4 + ret float %0 +} + +; CHECK-LABEL: ld_i32_test +; CHECK: ld [%o0], %o0 +; CHECK-NEXT: nop +define i32 @ld_i32_test(i32 *%p) { + %res = load i32, i32* %p + ret i32 %res +} + +; CHECK-LABEL: ld_inlineasm_test_1 +; CHECK: ld [%o0], %o0 +; CHECK-NEXT: !NO_APP +; CHECK-NEXT: nop +define float @ld_inlineasm_test_1(float* %a) { +entry: + %res = tail call float asm sideeffect "ld [$1], $0", "=r,r"(float* %a) + + ret float %res +} + +; CHECK-LABEL: ld_inlineasm_test_2 +; CHECK: ld [%o0], %o0 +; CHECK-NEXT: !NO_APP +; CHECK-NEXT: nop +define i32 @ld_inlineasm_test_2(i32* %a) { +entry: + %res = tail call i32 asm sideeffect "ld [$1], $0", "=r,r"(i32* %a) + + ret i32 %res +} \ No newline at end of file