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: Erratum Fix LBR35: 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,81 @@ +//===------ 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)/*, + TM(tm)*/ +{ +} + +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(); + + //errs() << "InsertNOPLoad on function " << MF.getName() << "\n"; + + 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) // this is an inline ld/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 @@ -119,12 +119,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, UMACSMACSupport, 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, UMACSMACSupport, LeonCASA, InsertNOPLoad]>; // LEON 4 FT generic def : Processor<"leon4", LEON4Itineraries, Index: lib/Target/Sparc/SparcISelLowering.cpp =================================================================== --- lib/Target/Sparc/SparcISelLowering.cpp +++ lib/Target/Sparc/SparcISelLowering.cpp @@ -1618,8 +1618,8 @@ if (Subtarget->isV9()) setMaxAtomicSizeInBitsSupported(64); else if (false && Subtarget->hasLeonCasa()) - // Test made to fail pending completion of AtomicExpandPass, - // as this will cause a regression until that work is completed. + // Test made to fail pending completion of AtomicExpandPass, + // as this will cause a regression until that work is completed. setMaxAtomicSizeInBitsSupported(32); else setMaxAtomicSizeInBitsSupported(0); Index: lib/Target/Sparc/SparcSubtarget.h =================================================================== --- lib/Target/Sparc/SparcSubtarget.h +++ lib/Target/Sparc/SparcSubtarget.h @@ -43,6 +43,7 @@ // LEON features bool HasUmacSmac; bool HasLeonCasa; + bool InsertNOPLoad; SparcInstrInfo InstrInfo; SparcTargetLowering TLInfo; @@ -81,6 +82,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 @@ -38,6 +38,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 @@ -34,6 +34,10 @@ return &Subtarget; } + const SparcSubtarget *getSubtarget() const { + return &Subtarget; + } + // Pass Pipeline Configuration TargetPassConfig *createPassConfig(PassManagerBase &PM) override; TargetLoweringObjectFile *getObjFileLowering() const override { 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" @@ -103,6 +104,11 @@ void SparcPassConfig::addPreEmitPass(){ addPass(createSparcDelaySlotFillerPass(getSparcTargetMachine())); + + if (this->getSparcTargetMachine().getSubtarget()->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