Index: include/llvm/Analysis/TargetTransformInfo.h =================================================================== --- include/llvm/Analysis/TargetTransformInfo.h +++ include/llvm/Analysis/TargetTransformInfo.h @@ -262,7 +262,7 @@ /// pointer with this address space is expected to be legal but slower /// compared to the same memory location accessed through a pointer with a /// different address space. - // + /// /// This is for for targets with different pointer representations which can /// be converted with the addrspacecast instruction. If a pointer is converted /// to this address space, optimizations should attempt to replace the access @@ -272,6 +272,14 @@ /// optimize away. unsigned getFlatAddressSpace() const; + /// Returns the address space ID that switch lookup tables should be placed + /// into. + /// + /// This is useful for Harvard architectures where you often want to place + /// lookup tables into a different address space (for example, in AVR, lookup + /// tables reside in the 'program memory' space. + unsigned getSwitchTableAddressSpace() const; + /// \brief Test whether calls to a function lower to actual program function /// calls. /// @@ -844,6 +852,8 @@ virtual bool isSourceOfDivergence(const Value *V) = 0; virtual bool isAlwaysUniform(const Value *V) = 0; virtual unsigned getFlatAddressSpace() = 0; + virtual unsigned getSwitchTableAddressSpace() const = 0; + virtual bool isLoweredToCall(const Function *F) = 0; virtual void getUnrollingPreferences(Loop *L, ScalarEvolution &, UnrollingPreferences &UP) = 0; @@ -1031,6 +1041,10 @@ return Impl.getFlatAddressSpace(); } + unsigned getSwitchTableAddressSpace() const override { + return Impl.getSwitchTableAddressSpace(); + } + bool isLoweredToCall(const Function *F) override { return Impl.isLoweredToCall(F); } Index: include/llvm/Analysis/TargetTransformInfoImpl.h =================================================================== --- include/llvm/Analysis/TargetTransformInfoImpl.h +++ include/llvm/Analysis/TargetTransformInfoImpl.h @@ -183,6 +183,8 @@ return -1; } + unsigned getSwitchTableAddressSpace() const { return 0; } + bool isLoweredToCall(const Function *F) { // FIXME: These should almost certainly not be handled here, and instead // handled with the help of TLI or the target itself. This was largely Index: include/llvm/CodeGen/BasicTTIImpl.h =================================================================== --- include/llvm/CodeGen/BasicTTIImpl.h +++ include/llvm/CodeGen/BasicTTIImpl.h @@ -100,6 +100,8 @@ return -1; } + unsigned getSwitchTableAddressSpace() const { return 0; } + bool isLegalAddImmediate(int64_t imm) { return getTLI()->isLegalAddImmediate(imm); } Index: lib/Analysis/TargetTransformInfo.cpp =================================================================== --- lib/Analysis/TargetTransformInfo.cpp +++ lib/Analysis/TargetTransformInfo.cpp @@ -112,6 +112,10 @@ return TTIImpl->getFlatAddressSpace(); } +unsigned TargetTransformInfo::getSwitchTableAddressSpace() const { + return TTIImpl->getSwitchTableAddressSpace(); +} + bool TargetTransformInfo::isLoweredToCall(const Function *F) const { return TTIImpl->isLoweredToCall(F); } Index: lib/Target/AVR/AVRTargetMachine.h =================================================================== --- lib/Target/AVR/AVRTargetMachine.h +++ lib/Target/AVR/AVRTargetMachine.h @@ -35,6 +35,8 @@ const AVRSubtarget *getSubtargetImpl() const; const AVRSubtarget *getSubtargetImpl(const Function &) const override; + TargetIRAnalysis getTargetIRAnalysis() override; + TargetLoweringObjectFile *getObjFileLowering() const override { return this->TLOF.get(); } Index: lib/Target/AVR/AVRTargetMachine.cpp =================================================================== --- lib/Target/AVR/AVRTargetMachine.cpp +++ lib/Target/AVR/AVRTargetMachine.cpp @@ -21,6 +21,7 @@ #include "AVR.h" #include "AVRTargetObjectFile.h" +#include "AVRTargetTransformInfo.h" #include "MCTargetDesc/AVRMCTargetDesc.h" namespace llvm { @@ -53,6 +54,12 @@ initAsmInfo(); } +TargetIRAnalysis AVRTargetMachine::getTargetIRAnalysis() { + return TargetIRAnalysis([this](const Function &F) { + return TargetTransformInfo(AVRTTIImpl(this, F)); + }); +} + namespace { /// AVR Code Generator Pass Configuration Options. class AVRPassConfig : public TargetPassConfig { Index: lib/Target/AVR/AVRTargetTransformInfo.h =================================================================== --- /dev/null +++ lib/Target/AVR/AVRTargetTransformInfo.h @@ -0,0 +1,49 @@ +//===---- AVRTargetTransformInfo.h - AVR specific TTI -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file a TargetTransformInfo::Concept conforming object specific to the +// AVR target machine. It uses the target's detailed information to +// provide more precise answers to certain TTI queries, while letting the +// target independent and default TTI implementations handle the rest. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_AVR_AVRTARGETTRANSFORMINFO_H +#define LLVM_LIB_TARGET_AVR_AVRTARGETTRANSFORMINFO_H + +#include "AVR.h" +#include "AVRSubtarget.h" +#include "AVRTargetMachine.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/BasicTTIImpl.h" +#include "llvm/Target/TargetLowering.h" + +namespace llvm { +class AVRTTIImpl : public BasicTTIImplBase { + typedef BasicTTIImplBase BaseT; + typedef TargetTransformInfo TTI; + friend BaseT; + + const AVRSubtarget *ST; + const AVRTargetLowering *TLI; + + const AVRSubtarget *getST() const { return ST; } + const AVRTargetLowering *getTLI() const { return TLI; } + +public: + explicit AVRTTIImpl(const AVRTargetMachine *TM, const Function &F) + : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)), + TLI(ST->getTargetLowering()) {} + + unsigned getSwitchTableAddressSpace() const { return AVR::ProgramMemory; } +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_AVR_AVRTARGETTRANSFORMINFO_H Index: lib/Target/AVR/LLVMBuild.txt =================================================================== --- lib/Target/AVR/LLVMBuild.txt +++ lib/Target/AVR/LLVMBuild.txt @@ -30,6 +30,17 @@ type = Library name = AVRCodeGen parent = AVR -required_libraries = AsmPrinter CodeGen Core MC AVRAsmPrinter AVRDesc AVRInfo SelectionDAG Support Target +required_libraries = + Analysis + AsmPrinter + CodeGen + Core + MC + AVRAsmPrinter + AVRDesc + AVRInfo + SelectionDAG + Support + Target add_to_library_groups = AVR Index: lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- lib/Transforms/Utils/SimplifyCFG.cpp +++ lib/Transforms/Utils/SimplifyCFG.cpp @@ -4781,7 +4781,8 @@ SwitchLookupTable( Module &M, uint64_t TableSize, ConstantInt *Offset, const SmallVectorImpl> &Values, - Constant *DefaultValue, const DataLayout &DL, const StringRef &FuncName); + Constant *DefaultValue, const DataLayout &DL, const StringRef &FuncName, + const TargetTransformInfo &TTI); /// Build instructions with Builder to retrieve the value at /// the position given by Index in the lookup table. @@ -4835,7 +4836,8 @@ SwitchLookupTable::SwitchLookupTable( Module &M, uint64_t TableSize, ConstantInt *Offset, const SmallVectorImpl> &Values, - Constant *DefaultValue, const DataLayout &DL, const StringRef &FuncName) + Constant *DefaultValue, const DataLayout &DL, const StringRef &FuncName, + const TargetTransformInfo &TTI) : SingleValue(nullptr), BitMap(nullptr), BitMapElementTy(nullptr), LinearOffset(nullptr), LinearMultiplier(nullptr), Array(nullptr) { assert(Values.size() && "Can't build lookup table without values!"); @@ -4943,7 +4945,10 @@ Array = new GlobalVariable(M, ArrayTy, /*constant=*/true, GlobalVariable::PrivateLinkage, Initializer, - "switch.table." + FuncName); + "switch.table." + FuncName, + /*InsertBefore=*/nullptr, + GlobalValue::NotThreadLocal, + TTI.getSwitchTableAddressSpace()); Array->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); Kind = ArrayKind; } @@ -5335,7 +5340,7 @@ Constant *DV = NeedMask ? ResultLists[PHI][0].second : DefaultResults[PHI]; StringRef FuncName = SI->getParent()->getParent()->getName(); SwitchLookupTable Table(Mod, TableSize, MinCaseVal, ResultList, DV, DL, - FuncName); + FuncName, TTI); Value *Result = Table.BuildLookup(TableIndex, Builder); Index: test/CodeGen/AVR/switch-lookup-table-in-progmem-space.ll =================================================================== --- /dev/null +++ test/CodeGen/AVR/switch-lookup-table-in-progmem-space.ll @@ -0,0 +1,61 @@ +; RUN: opt -S -mtriple=avr -latesimplifycfg < %s | FileCheck %s + +; Switch lookup tables should be placed in program memory (address space 1). + +%MyType = type { i8, [0 x i8], [0 x i8] } + +define i8 @foo(i8) { +start: + %_0 = alloca %MyType + +; CHECK: @switch.table.foo = {{.*}}addrspace(1) constant [15 x i8] c"\01\01\01\01\01\00\00\00\00\00\00\00\00\00\01" + switch i8 %0, label %bb7 [ + i8 0, label %bb1 + i8 1, label %bb2 + i8 2, label %bb3 + i8 3, label %bb4 + i8 4, label %bb5 + i8 14, label %bb6 + ] + +bb1: + %1 = getelementptr inbounds %MyType, %MyType* %_0, i32 0, i32 0 + store i8 1, i8* %1 + br label %bb8 + +bb2: + %2 = getelementptr inbounds %MyType, %MyType* %_0, i32 0, i32 0 + store i8 1, i8* %2 + br label %bb8 + +bb3: + %3 = getelementptr inbounds %MyType, %MyType* %_0, i32 0, i32 0 + store i8 1, i8* %3 + br label %bb8 + +bb4: + %4 = getelementptr inbounds %MyType, %MyType* %_0, i32 0, i32 0 + store i8 1, i8* %4 + br label %bb8 + +bb5: + %5 = getelementptr inbounds %MyType, %MyType* %_0, i32 0, i32 0 + store i8 1, i8* %5 + br label %bb8 + +bb6: + %6 = getelementptr inbounds %MyType, %MyType* %_0, i32 0, i32 0 + store i8 1, i8* %6 + br label %bb8 + +bb7: + %7 = getelementptr inbounds %MyType, %MyType* %_0, i32 0, i32 0 + store i8 0, i8* %7 + br label %bb8 + +bb8: + %8 = bitcast %MyType* %_0 to i8* + %9 = load i8, i8* %8, align 1 + ret i8 %9 +} +