summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/Target/AVR
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Target/AVR')
-rw-r--r--contrib/llvm/lib/Target/AVR/AVR.h6
-rw-r--r--contrib/llvm/lib/Target/AVR/AVR.td526
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRAsmPrinter.cpp184
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRCallingConv.td11
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRDevices.td491
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp1515
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRFrameLowering.cpp538
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp565
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRISelLowering.cpp1978
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRISelLowering.h18
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRInstrFormats.td2
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRInstrInfo.cpp82
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRInstrInfo.h12
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRInstrInfo.td114
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRInstrumentFunctions.cpp222
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRMCInstLower.cpp100
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRMCInstLower.h43
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRRegisterInfo.cpp20
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRRegisterInfo.h6
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp149
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRTargetMachine.cpp25
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp9
-rw-r--r--contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.h3
-rw-r--r--contrib/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp631
-rw-r--r--contrib/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp156
-rw-r--r--contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.cpp171
-rw-r--r--contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.h54
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp473
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.h78
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp127
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRFixupKinds.h149
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp304
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.h115
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp189
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h88
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.cpp121
-rw-r--r--contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h6
-rw-r--r--contrib/llvm/lib/Target/AVR/README.md8
-rw-r--r--contrib/llvm/lib/Target/AVR/TargetInfo/AVRTargetInfo.cpp14
39 files changed, 8705 insertions, 598 deletions
diff --git a/contrib/llvm/lib/Target/AVR/AVR.h b/contrib/llvm/lib/Target/AVR/AVR.h
index 041c77c..8e5cc53 100644
--- a/contrib/llvm/lib/Target/AVR/AVR.h
+++ b/contrib/llvm/lib/Target/AVR/AVR.h
@@ -27,9 +27,15 @@ FunctionPass *createAVRISelDag(AVRTargetMachine &TM,
CodeGenOpt::Level OptLevel);
FunctionPass *createAVRExpandPseudoPass();
FunctionPass *createAVRFrameAnalyzerPass();
+FunctionPass *createAVRInstrumentFunctionsPass();
+FunctionPass *createAVRRelaxMemPass();
FunctionPass *createAVRDynAllocaSRPass();
FunctionPass *createAVRBranchSelectionPass();
+void initializeAVRExpandPseudoPass(PassRegistry&);
+void initializeAVRInstrumentFunctionsPass(PassRegistry&);
+void initializeAVRRelaxMemPass(PassRegistry&);
+
/// Contains the AVR backend.
namespace AVR {
diff --git a/contrib/llvm/lib/Target/AVR/AVR.td b/contrib/llvm/lib/Target/AVR/AVR.td
index 27cf212..d03b983 100644
--- a/contrib/llvm/lib/Target/AVR/AVR.td
+++ b/contrib/llvm/lib/Target/AVR/AVR.td
@@ -16,493 +16,10 @@
include "llvm/Target/Target.td"
//===---------------------------------------------------------------------===//
-// AVR Subtarget Features.
+// AVR Device Definitions
//===---------------------------------------------------------------------===//
-// :TODO: Implement the skip errata, see `gcc/config/avr/avr-arch.h` for details
-// :TODO: We define all devices with SRAM to have all variants of LD/ST/LDD/STD.
-// In reality, avr1 (no SRAM) has one variant each of `LD` and `ST`.
-// avr2 (with SRAM) adds the rest of the variants.
-// :TODO: s/AVRTiny/Tiny
-
-
-// A feature set aggregates features, grouping them. We don't want to create a
-// new member in AVRSubtarget (to store a value) for each set because we do not
-// care if the set is supported, only the subfeatures inside the set. We fix
-// this by simply setting the same dummy member for all feature sets, which is
-// then ignored.
-class FeatureSet<string name, string desc, list<SubtargetFeature> i>
- : SubtargetFeature<name, "m_FeatureSetDummy", "true", desc, i>;
-
-// A family of microcontrollers, defining a set of supported features.
-class Family<string name, list<SubtargetFeature> i>
- : FeatureSet<name, !strconcat("The device is a part of the ",
- name, " family"), i>;
-
-// The device has SRAM, and supports the bare minimum of
-// SRAM-relevant instructions.
-//
-// These are:
-// LD - all 9 variants
-// ST - all 9 variants
-// LDD - two variants for Y and Z
-// STD - two variants for Y and Z
-// `LDS Rd, K`
-// `STS k, Rr`
-// `PUSH`/`POP`
-def FeatureSRAM : SubtargetFeature<"sram", "m_hasSRAM", "true",
- "The device has random access memory">;
-
-// The device supports the `JMP k` and `CALL k` instructions.
-def FeatureJMPCALL : SubtargetFeature<"jmpcall", "m_hasJMPCALL", "true",
- "The device supports the `JMP` and "
- "`CALL` instructions">;
-
-
-// The device supports the indirect branches `IJMP` and `ICALL`.
-def FeatureIJMPCALL : SubtargetFeature<"ijmpcall", "m_hasIJMPCALL",
- "true",
- "The device supports `IJMP`/`ICALL`"
- "instructions">;
-
-// The device supports the extended indirect branches `EIJMP` and `EICALL`.
-def FeatureEIJMPCALL : SubtargetFeature<"eijmpcall", "m_hasEIJMPCALL",
- "true", "The device supports the "
- "`EIJMP`/`EICALL` instructions">;
-
-// The device supports `ADDI Rd, K`, `SUBI Rd, K`.
-def FeatureADDSUBIW : SubtargetFeature<"addsubiw", "m_hasADDSUBIW",
- "true", "Enable 16-bit register-immediate "
- "addition and subtraction instructions">;
-
-// The device has an 8-bit stack pointer (SP) register.
-def FeatureSmallStack : SubtargetFeature<"smallstack", "m_hasSmallStack",
- "true", "The device has an 8-bit "
- "stack pointer">;
-
-// The device supports the 16-bit GPR pair MOVW instruction.
-def FeatureMOVW : SubtargetFeature<"movw", "m_hasMOVW", "true",
- "The device supports the 16-bit MOVW "
- "instruction">;
-
-// The device supports the `LPM` instruction, with implied destination being r0.
-def FeatureLPM : SubtargetFeature<"lpm", "m_hasLPM", "true",
- "The device supports the `LPM` instruction">;
-
-// The device supports the `LPM Rd, Z[+] instruction.
-def FeatureLPMX : SubtargetFeature<"lpmx", "m_hasLPMX", "true",
- "The device supports the `LPM Rd, Z[+]` "
- "instruction">;
-
-// The device supports the `ELPM` instruction.
-def FeatureELPM : SubtargetFeature<"elpm", "m_hasELPM", "true",
- "The device supports the ELPM instruction">;
-
-// The device supports the `ELPM Rd, Z[+]` instructions.
-def FeatureELPMX : SubtargetFeature<"elpmx", "m_hasELPMX", "true",
- "The device supports the `ELPM Rd, Z[+]` "
- "instructions">;
-
-// The device supports the `SPM` instruction.
-def FeatureSPM : SubtargetFeature<"spm", "m_hasSPM", "true",
- "The device supports the `SPM` instruction">;
-
-// The device supports the `SPM Z+` instruction.
-def FeatureSPMX : SubtargetFeature<"spmx", "m_hasSPMX", "true",
- "The device supports the `SPM Z+` "
- "instruction">;
-
-// The device supports the `DES k` instruction.
-def FeatureDES : SubtargetFeature<"des", "m_hasDES", "true",
- "The device supports the `DES k` encryption "
- "instruction">;
-
-// The device supports the Read-Write-Modify instructions
-// XCH, LAS, LAC, and LAT.
-def FeatureRMW : SubtargetFeature<"rmw", "m_supportsRMW", "true",
- "The device supports the read-write-modify "
- "instructions: XCH, LAS, LAC, LAT">;
-
-// The device supports the `[F]MUL[S][U]` family of instructions.
-def FeatureMultiplication : SubtargetFeature<"mul", "m_supportsMultiplication",
- "true", "The device supports the "
- "multiplication instructions">;
-
-// The device supports the `BREAK` instruction.
-def FeatureBREAK : SubtargetFeature<"break", "m_hasBREAK", "true",
- "The device supports the `BREAK` debugging "
- "instruction">;
-
-// The device has instruction encodings specific to the Tiny core.
-def FeatureTinyEncoding : SubtargetFeature<"tinyencoding",
- "m_hasTinyEncoding", "true",
- "The device has Tiny core specific "
- "instruction encodings">;
-
-class ELFArch<string name> : SubtargetFeature<"", "ELFArch",
- !strconcat("ELF::",name), "">;
-
-// ELF e_flags architecture values
-def ELFArchAVR1 : ELFArch<"EF_AVR_ARCH_AVR1">;
-def ELFArchAVR2 : ELFArch<"EF_AVR_ARCH_AVR2">;
-def ELFArchAVR25 : ELFArch<"EF_AVR_ARCH_AVR25">;
-def ELFArchAVR3 : ELFArch<"EF_AVR_ARCH_AVR3">;
-def ELFArchAVR31 : ELFArch<"EF_AVR_ARCH_AVR31">;
-def ELFArchAVR35 : ELFArch<"EF_AVR_ARCH_AVR35">;
-def ELFArchAVR4 : ELFArch<"EF_AVR_ARCH_AVR4">;
-def ELFArchAVR5 : ELFArch<"EF_AVR_ARCH_AVR5">;
-def ELFArchAVR51 : ELFArch<"EF_AVR_ARCH_AVR51">;
-def ELFArchAVR6 : ELFArch<"EF_AVR_ARCH_AVR6">;
-def ELFArchAVRTiny : ELFArch<"EF_AVR_ARCH_AVRTINY">;
-def ELFArchXMEGA1 : ELFArch<"EF_AVR_ARCH_XMEGA1">;
-def ELFArchXMEGA2 : ELFArch<"EF_AVR_ARCH_XMEGA2">;
-def ELFArchXMEGA3 : ELFArch<"EF_AVR_ARCH_XMEGA3">;
-def ELFArchXMEGA4 : ELFArch<"EF_AVR_ARCH_XMEGA4">;
-def ELFArchXMEGA5 : ELFArch<"EF_AVR_ARCH_XMEGA5">;
-def ELFArchXMEGA6 : ELFArch<"EF_AVR_ARCH_XMEGA6">;
-def ELFArchXMEGA7 : ELFArch<"EF_AVR_ARCH_XMEGA7">;
-
-//===---------------------------------------------------------------------===//
-// AVR Families
-//===---------------------------------------------------------------------===//
-
-// The device has at least the bare minimum that **every** single AVR
-// device should have.
-def FamilyAVR0 : Family<"avr0", []>;
-
-def FamilyAVR1 : Family<"avr1", [FamilyAVR0, FeatureLPM]>;
-
-def FamilyAVR2 : Family<"avr2",
- [FamilyAVR1, FeatureIJMPCALL, FeatureADDSUBIW,
- FeatureSRAM]>;
-
-def FamilyAVR25 : Family<"avr25",
- [FamilyAVR2, FeatureMOVW, FeatureLPMX,
- FeatureSPM, FeatureBREAK]>;
-
-def FamilyAVR3 : Family<"avr3",
- [FamilyAVR2, FeatureJMPCALL]>;
-
-def FamilyAVR31 : Family<"avr31",
- [FamilyAVR3, FeatureELPM]>;
-
-def FamilyAVR35 : Family<"avr35",
- [FamilyAVR3, FeatureMOVW, FeatureLPMX,
- FeatureSPM, FeatureBREAK]>;
-
-def FamilyAVR4 : Family<"avr4",
- [FamilyAVR2, FeatureMultiplication,
- FeatureMOVW, FeatureLPMX, FeatureSPM,
- FeatureBREAK]>;
-
-def FamilyAVR5 : Family<"avr5",
- [FamilyAVR3, FeatureMultiplication,
- FeatureMOVW, FeatureLPMX, FeatureSPM,
- FeatureBREAK]>;
-
-def FamilyAVR51 : Family<"avr51",
- [FamilyAVR5, FeatureELPM, FeatureELPMX]>;
-
-def FamilyAVR6 : Family<"avr6",
- [FamilyAVR51]>;
-
-def FamilyAVRTiny : Family<"avrtiny",
- [FamilyAVR0, FeatureBREAK, FeatureSRAM,
- FeatureTinyEncoding]>;
-
-def FamilyXMEGA : Family<"xmega",
- [FamilyAVR51, FeatureEIJMPCALL, FeatureSPMX,
- FeatureDES]>;
-
-def FamilyXMEGAU : Family<"xmegau",
- [FamilyXMEGA, FeatureRMW]>;
-
-def FeatureSetSpecial : FeatureSet<"special",
- "Enable use of the entire instruction "
- "set - used for debugging",
- [FeatureSRAM, FeatureJMPCALL,
- FeatureIJMPCALL, FeatureEIJMPCALL,
- FeatureADDSUBIW, FeatureMOVW,
- FeatureLPM, FeatureLPMX, FeatureELPM,
- FeatureELPMX, FeatureSPM, FeatureSPMX,
- FeatureDES, FeatureRMW,
- FeatureMultiplication, FeatureBREAK]>;
-
-//===---------------------------------------------------------------------===//
-// AVR microcontrollers supported.
-//===---------------------------------------------------------------------===//
-
-class Device<string Name, Family Fam, ELFArch Arch,
- list<SubtargetFeature> ExtraFeatures = []>
- : Processor<Name, NoItineraries, !listconcat([Fam,Arch],ExtraFeatures)>;
-
-// Generic MCUs
-// Note that several versions of GCC has strange ELF architecture
-// settings for backwards compatibility - see `gas/config/tc-avr.c`
-// in AVR binutils. We do not replicate this.
-def : Device<"avr1", FamilyAVR1, ELFArchAVR1>;
-def : Device<"avr2", FamilyAVR2, ELFArchAVR2>;
-def : Device<"avr25", FamilyAVR25, ELFArchAVR25>;
-def : Device<"avr3", FamilyAVR3, ELFArchAVR3>;
-def : Device<"avr31", FamilyAVR31, ELFArchAVR31>;
-def : Device<"avr35", FamilyAVR35, ELFArchAVR35>;
-def : Device<"avr4", FamilyAVR4, ELFArchAVR4>;
-def : Device<"avr5", FamilyAVR5, ELFArchAVR5>;
-def : Device<"avr51", FamilyAVR51, ELFArchAVR51>;
-def : Device<"avr6", FamilyAVR6, ELFArchAVR6>;
-def : Device<"avrxmega1", FamilyXMEGA, ELFArchXMEGA1>;
-def : Device<"avrxmega2", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"avrxmega3", FamilyXMEGA, ELFArchXMEGA3>;
-def : Device<"avrxmega4", FamilyXMEGA, ELFArchXMEGA4>;
-def : Device<"avrxmega5", FamilyXMEGA, ELFArchXMEGA5>;
-def : Device<"avrxmega6", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"avrxmega7", FamilyXMEGA, ELFArchXMEGA7>;
-def : Device<"avrtiny", FamilyAVRTiny, ELFArchAVRTiny>;
-
-// Specific MCUs
-def : Device<"at90s1200", FamilyAVR0, ELFArchAVR1>;
-def : Device<"attiny11", FamilyAVR1, ELFArchAVR1>;
-def : Device<"attiny12", FamilyAVR1, ELFArchAVR1>;
-def : Device<"attiny15", FamilyAVR1, ELFArchAVR1>;
-def : Device<"attiny28", FamilyAVR1, ELFArchAVR1>;
-def : Device<"at90s2313", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s2323", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s2333", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s2343", FamilyAVR2, ELFArchAVR2>;
-def : Device<"attiny22", FamilyAVR2, ELFArchAVR2>;
-def : Device<"attiny26", FamilyAVR2, ELFArchAVR2, [FeatureLPMX]>;
-def : Device<"at86rf401", FamilyAVR2, ELFArchAVR25,
- [FeatureMOVW, FeatureLPMX]>;
-def : Device<"at90s4414", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s4433", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s4434", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s8515", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90c8534", FamilyAVR2, ELFArchAVR2>;
-def : Device<"at90s8535", FamilyAVR2, ELFArchAVR2>;
-def : Device<"ata5272", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny13", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny13a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny2313", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny2313a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny24", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny24a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny4313", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny44", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny44a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny84", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny84a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny25", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny45", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny85", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny261", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny261a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny461", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny461a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny861", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny861a", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny87", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny43u", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny48", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny88", FamilyAVR25, ELFArchAVR25>;
-def : Device<"attiny828", FamilyAVR25, ELFArchAVR25>;
-def : Device<"at43usb355", FamilyAVR3, ELFArchAVR3>;
-def : Device<"at76c711", FamilyAVR3, ELFArchAVR3>;
-def : Device<"atmega103", FamilyAVR31, ELFArchAVR31>;
-def : Device<"at43usb320", FamilyAVR31, ELFArchAVR31>;
-def : Device<"attiny167", FamilyAVR35, ELFArchAVR35>;
-def : Device<"at90usb82", FamilyAVR35, ELFArchAVR35>;
-def : Device<"at90usb162", FamilyAVR35, ELFArchAVR35>;
-def : Device<"ata5505", FamilyAVR35, ELFArchAVR35>;
-def : Device<"atmega8u2", FamilyAVR35, ELFArchAVR35>;
-def : Device<"atmega16u2", FamilyAVR35, ELFArchAVR35>;
-def : Device<"atmega32u2", FamilyAVR35, ELFArchAVR35>;
-def : Device<"attiny1634", FamilyAVR35, ELFArchAVR35>;
-def : Device<"atmega8", FamilyAVR4, ELFArchAVR4>; // FIXME: family may be wrong
-def : Device<"ata6289", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega8a", FamilyAVR4, ELFArchAVR4>;
-def : Device<"ata6285", FamilyAVR4, ELFArchAVR4>;
-def : Device<"ata6286", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega48", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega48a", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega48pa", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega48p", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega88", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega88a", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega88p", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega88pa", FamilyAVR4, ELFArchAVR4>;
-def : Device<"atmega8515", FamilyAVR2, ELFArchAVR4,
- [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
-def : Device<"atmega8535", FamilyAVR2, ELFArchAVR4,
- [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
-def : Device<"atmega8hva", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm1", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm2", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm2b", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm3", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm3b", FamilyAVR4, ELFArchAVR4>;
-def : Device<"at90pwm81", FamilyAVR4, ELFArchAVR4>;
-def : Device<"ata5790", FamilyAVR5, ELFArchAVR5>;
-def : Device<"ata5795", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega161", FamilyAVR3, ELFArchAVR5,
- [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
-def : Device<"atmega162", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega163", FamilyAVR3, ELFArchAVR5,
- [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
-def : Device<"atmega164a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega164p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega164pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega165", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega165a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega165p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega165pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega168", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega168a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega168p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega168pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega169", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega169a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega169p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega169pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega323", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega324a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega324p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega324pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega325", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega325a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega325p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega325pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3250", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3250a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3250p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3250pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega328", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega328p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega329", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega329a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega329p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega329pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3290", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3290a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3290p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega3290pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega406", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega640", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega644", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega644a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega644p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega644pa", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega645", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega645a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega645p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega649", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega649a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega649p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6450", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6450a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6450p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6490", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6490a", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega6490p", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64rfr2", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega644rfr2", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16hva", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16hva2", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16hvb", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16hvbrevb", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32hvb", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32hvbrevb", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64hve", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90can32", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90can64", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90pwm161", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90pwm216", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90pwm316", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32c1", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64c1", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16m1", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32m1", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega64m1", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega16u4", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32u4", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega32u6", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90usb646", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90usb647", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at90scr100", FamilyAVR5, ELFArchAVR5>;
-def : Device<"at94k", FamilyAVR3, ELFArchAVR5,
- [FeatureMultiplication, FeatureMOVW, FeatureLPMX]>;
-def : Device<"m3000", FamilyAVR5, ELFArchAVR5>;
-def : Device<"atmega128", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega128a", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega1280", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega1281", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega1284", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega1284p", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega128rfa1", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega128rfr2", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega1284rfr2", FamilyAVR51, ELFArchAVR51>;
-def : Device<"at90can128", FamilyAVR51, ELFArchAVR51>;
-def : Device<"at90usb1286", FamilyAVR51, ELFArchAVR51>;
-def : Device<"at90usb1287", FamilyAVR51, ELFArchAVR51>;
-def : Device<"atmega2560", FamilyAVR6, ELFArchAVR6>;
-def : Device<"atmega2561", FamilyAVR6, ELFArchAVR6>;
-def : Device<"atmega256rfr2", FamilyAVR6, ELFArchAVR6>;
-def : Device<"atmega2564rfr2", FamilyAVR6, ELFArchAVR6>;
-def : Device<"atxmega16a4", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega16a4u", FamilyXMEGAU, ELFArchXMEGA2>;
-def : Device<"atxmega16c4", FamilyXMEGAU, ELFArchXMEGA2>;
-def : Device<"atxmega16d4", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega32a4", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega32a4u", FamilyXMEGAU, ELFArchXMEGA2>;
-def : Device<"atxmega32c4", FamilyXMEGAU, ELFArchXMEGA2>;
-def : Device<"atxmega32d4", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega32e5", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega16e5", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega8e5", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega32x1", FamilyXMEGA, ELFArchXMEGA2>;
-def : Device<"atxmega64a3", FamilyXMEGA, ELFArchXMEGA4>;
-def : Device<"atxmega64a3u", FamilyXMEGAU, ELFArchXMEGA4>;
-def : Device<"atxmega64a4u", FamilyXMEGAU, ELFArchXMEGA4>;
-def : Device<"atxmega64b1", FamilyXMEGAU, ELFArchXMEGA4>;
-def : Device<"atxmega64b3", FamilyXMEGAU, ELFArchXMEGA4>;
-def : Device<"atxmega64c3", FamilyXMEGAU, ELFArchXMEGA4>;
-def : Device<"atxmega64d3", FamilyXMEGA, ELFArchXMEGA4>;
-def : Device<"atxmega64d4", FamilyXMEGA, ELFArchXMEGA4>;
-def : Device<"atxmega64a1", FamilyXMEGA, ELFArchXMEGA5>;
-def : Device<"atxmega64a1u", FamilyXMEGAU, ELFArchXMEGA5>;
-def : Device<"atxmega128a3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega128a3u", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega128b1", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega128b3", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega128c3", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega128d3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega128d4", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega192a3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega192a3u", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega192c3", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega192d3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega256a3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega256a3u", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega256a3b", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega256a3bu", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega256c3", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega256d3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega384c3", FamilyXMEGAU, ELFArchXMEGA6>;
-def : Device<"atxmega384d3", FamilyXMEGA, ELFArchXMEGA6>;
-def : Device<"atxmega128a1", FamilyXMEGA, ELFArchXMEGA7>;
-def : Device<"atxmega128a1u", FamilyXMEGAU, ELFArchXMEGA7>;
-def : Device<"atxmega128a4u", FamilyXMEGAU, ELFArchXMEGA7>;
-def : Device<"attiny4", FamilyAVRTiny, ELFArchAVRTiny>;
-def : Device<"attiny5", FamilyAVRTiny, ELFArchAVRTiny>;
-def : Device<"attiny9", FamilyAVRTiny, ELFArchAVRTiny>;
-def : Device<"attiny10", FamilyAVRTiny, ELFArchAVRTiny>;
-def : Device<"attiny20", FamilyAVRTiny, ELFArchAVRTiny>;
-def : Device<"attiny40", FamilyAVRTiny, ELFArchAVRTiny>;
+include "AVRDevices.td"
//===---------------------------------------------------------------------===//
// Register File Description
@@ -528,36 +45,37 @@ include "AVRCallingConv.td"
// Assembly Printers
//===---------------------------------------------------------------------===//
-// def AVRAsmWriter : AsmWriter {
-// string AsmWriterClassName = "InstPrinter";
-// bit isMCAsmWriter = 1;
-// }
+def AVRAsmWriter : AsmWriter {
+ string AsmWriterClassName = "InstPrinter";
+ bit isMCAsmWriter = 1;
+}
//===---------------------------------------------------------------------===//
// Assembly Parsers
//===---------------------------------------------------------------------===//
-// def AVRAsmParser : AsmParser {
-// let ShouldEmitMatchRegisterName = 1;
-// let ShouldEmitMatchRegisterAltName = 1;
-// }
+def AVRAsmParser : AsmParser {
+ let ShouldEmitMatchRegisterName = 1;
+ let ShouldEmitMatchRegisterAltName = 1;
+}
-// def AVRAsmParserVariant : AsmParserVariant {
-// int Variant = 0;
-//
-// // Recognize hard coded registers.
-// string RegisterPrefix = "$";
-// }
+def AVRAsmParserVariant : AsmParserVariant {
+ int Variant = 0;
+
+ // Recognize hard coded registers.
+ string RegisterPrefix = "$";
+ string TokenizingCharacters = "+";
+}
//===---------------------------------------------------------------------===//
// Target Declaration
//===---------------------------------------------------------------------===//
def AVR : Target {
- let InstructionSet = AVRInstrInfo;
-// let AssemblyWriters = [AVRAsmWriter];
-//
-// let AssemblyParsers = [AVRAsmParser];
-// let AssemblyParserVariants = [AVRAsmParserVariant];
+ let InstructionSet = AVRInstrInfo;
+ let AssemblyWriters = [AVRAsmWriter];
+
+ let AssemblyParsers = [AVRAsmParser];
+ let AssemblyParserVariants = [AVRAsmParserVariant];
}
diff --git a/contrib/llvm/lib/Target/AVR/AVRAsmPrinter.cpp b/contrib/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
new file mode 100644
index 0000000..4afdd3a
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRAsmPrinter.cpp
@@ -0,0 +1,184 @@
+//===-- AVRAsmPrinter.cpp - AVR LLVM assembly writer ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a printer that converts from our internal representation
+// of machine-dependent LLVM code to GAS-format AVR assembly language.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRMCInstLower.h"
+#include "AVRSubtarget.h"
+#include "InstPrinter/AVRInstPrinter.h"
+
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
+
+#define DEBUG_TYPE "avr-asm-printer"
+
+namespace llvm {
+
+/// An AVR assembly code printer.
+class AVRAsmPrinter : public AsmPrinter {
+public:
+ AVRAsmPrinter(TargetMachine &TM,
+ std::unique_ptr<MCStreamer> Streamer)
+ : AsmPrinter(TM, std::move(Streamer)), MRI(*TM.getMCRegisterInfo()) { }
+
+ StringRef getPassName() const override { return "AVR Assembly Printer"; }
+
+ void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O,
+ const char *Modifier = 0);
+
+ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &O) override;
+
+ bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &O) override;
+
+ void EmitInstruction(const MachineInstr *MI) override;
+
+private:
+ const MCRegisterInfo &MRI;
+};
+
+void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
+ raw_ostream &O, const char *Modifier) {
+ const MachineOperand &MO = MI->getOperand(OpNo);
+
+ switch (MO.getType()) {
+ case MachineOperand::MO_Register:
+ O << AVRInstPrinter::getPrettyRegisterName(MO.getReg(), MRI);
+ break;
+ case MachineOperand::MO_Immediate:
+ O << MO.getImm();
+ break;
+ case MachineOperand::MO_GlobalAddress:
+ O << getSymbol(MO.getGlobal());
+ break;
+ case MachineOperand::MO_ExternalSymbol:
+ O << *GetExternalSymbolSymbol(MO.getSymbolName());
+ break;
+ case MachineOperand::MO_MachineBasicBlock:
+ O << *MO.getMBB()->getSymbol();
+ break;
+ default:
+ llvm_unreachable("Not implemented yet!");
+ }
+}
+
+bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &O) {
+ // Default asm printer can only deal with some extra codes,
+ // so try it first.
+ bool Error = AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O);
+
+ if (Error && ExtraCode && ExtraCode[0]) {
+ if (ExtraCode[1] != 0)
+ return true; // Unknown modifier.
+
+ if (ExtraCode[0] >= 'A' && ExtraCode[0] <= 'Z') {
+ const MachineOperand &RegOp = MI->getOperand(OpNum);
+
+ assert(RegOp.isReg() && "Operand must be a register when you're"
+ "using 'A'..'Z' operand extracodes.");
+ unsigned Reg = RegOp.getReg();
+
+ unsigned ByteNumber = ExtraCode[0] - 'A';
+
+ unsigned OpFlags = MI->getOperand(OpNum - 1).getImm();
+ unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags);
+ (void)NumOpRegs;
+
+ const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
+ const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
+
+ unsigned BytesPerReg = TRI.getMinimalPhysRegClass(Reg)->getSize();
+ assert(BytesPerReg <= 2 && "Only 8 and 16 bit regs are supported.");
+
+ unsigned RegIdx = ByteNumber / BytesPerReg;
+ assert(RegIdx < NumOpRegs && "Multibyte index out of range.");
+
+ Reg = MI->getOperand(OpNum + RegIdx).getReg();
+
+ if (BytesPerReg == 2) {
+ Reg = TRI.getSubReg(Reg, ByteNumber % BytesPerReg ? AVR::sub_hi
+ : AVR::sub_lo);
+ }
+
+ O << AVRInstPrinter::getPrettyRegisterName(Reg, MRI);
+ return false;
+ }
+ }
+
+ printOperand(MI, OpNum, O);
+
+ return false;
+}
+
+bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
+ unsigned OpNum, unsigned AsmVariant,
+ const char *ExtraCode,
+ raw_ostream &O) {
+ if (ExtraCode && ExtraCode[0]) {
+ llvm_unreachable("This branch is not implemented yet");
+ }
+
+ const MachineOperand &MO = MI->getOperand(OpNum);
+ (void)MO;
+ assert(MO.isReg() && "Unexpected inline asm memory operand");
+
+ // TODO: We can look up the alternative name for the register if it's given.
+ if (MI->getOperand(OpNum).getReg() == AVR::R31R30) {
+ O << "Z";
+ } else {
+ assert(MI->getOperand(OpNum).getReg() == AVR::R29R28 &&
+ "Wrong register class for memory operand.");
+ O << "Y";
+ }
+
+ // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion
+ // and the second operand is an Imm.
+ unsigned OpFlags = MI->getOperand(OpNum - 1).getImm();
+ unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags);
+
+ if (NumOpRegs == 2) {
+ O << '+' << MI->getOperand(OpNum + 1).getImm();
+ }
+
+ return false;
+}
+
+void AVRAsmPrinter::EmitInstruction(const MachineInstr *MI) {
+ AVRMCInstLower MCInstLowering(OutContext, *this);
+
+ MCInst I;
+ MCInstLowering.lowerInstruction(*MI, I);
+ EmitToStreamer(*OutStreamer, I);
+}
+
+} // end of namespace llvm
+
+extern "C" void LLVMInitializeAVRAsmPrinter() {
+ llvm::RegisterAsmPrinter<llvm::AVRAsmPrinter> X(llvm::getTheAVRTarget());
+}
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRCallingConv.td b/contrib/llvm/lib/Target/AVR/AVRCallingConv.td
index d8cb3fe..68dbce0 100644
--- a/contrib/llvm/lib/Target/AVR/AVRCallingConv.td
+++ b/contrib/llvm/lib/Target/AVR/AVRCallingConv.td
@@ -23,7 +23,7 @@ def RetCC_AVR : CallingConv
]>;
// Special return value calling convention for runtime functions.
-def RetCC_AVR_RT : CallingConv
+def RetCC_AVR_BUILTIN : CallingConv
<[
CCIfType<[i8], CCAssignToReg<[R24,R25]>>,
CCIfType<[i16], CCAssignToReg<[R23R22, R25R24]>>
@@ -43,15 +43,8 @@ def ArgCC_AVR_Vararg : CallingConv
]>;
// Special argument calling convention for
-// multiplication runtime functions.
-def ArgCC_AVR_RT_MUL : CallingConv
-<[
- CCIfType<[i16], CCAssignToReg<[R27R26,R19R18]>>
-]>;
-
-// Special argument calling convention for
// division runtime functions.
-def ArgCC_AVR_RT_DIV : CallingConv
+def ArgCC_AVR_BUILTIN_DIV : CallingConv
<[
CCIfType<[i8], CCAssignToReg<[R24,R22]>>,
CCIfType<[i16], CCAssignToReg<[R25R24, R23R22]>>
diff --git a/contrib/llvm/lib/Target/AVR/AVRDevices.td b/contrib/llvm/lib/Target/AVR/AVRDevices.td
new file mode 100644
index 0000000..9224af6
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRDevices.td
@@ -0,0 +1,491 @@
+//===---------------------------------------------------------------------===//
+// AVR Device Definitions
+//===---------------------------------------------------------------------===//
+
+// :TODO: Implement the skip errata, see `gcc/config/avr/avr-arch.h` for details
+// :TODO: We define all devices with SRAM to have all variants of LD/ST/LDD/STD.
+// In reality, avr1 (no SRAM) has one variant each of `LD` and `ST`.
+// avr2 (with SRAM) adds the rest of the variants.
+// :TODO: s/AVRTiny/Tiny
+
+
+// A feature set aggregates features, grouping them. We don't want to create a
+// new member in AVRSubtarget (to store a value) for each set because we do not
+// care if the set is supported, only the subfeatures inside the set. We fix
+// this by simply setting the same dummy member for all feature sets, which is
+// then ignored.
+class FeatureSet<string name, string desc, list<SubtargetFeature> i>
+ : SubtargetFeature<name, "m_FeatureSetDummy", "true", desc, i>;
+
+// A family of microcontrollers, defining a set of supported features.
+class Family<string name, list<SubtargetFeature> i>
+ : FeatureSet<name, !strconcat("The device is a part of the ",
+ name, " family"), i>;
+
+// The device has SRAM, and supports the bare minimum of
+// SRAM-relevant instructions.
+//
+// These are:
+// LD - all 9 variants
+// ST - all 9 variants
+// LDD - two variants for Y and Z
+// STD - two variants for Y and Z
+// `LDS Rd, K`
+// `STS k, Rr`
+// `PUSH`/`POP`
+def FeatureSRAM : SubtargetFeature<"sram", "m_hasSRAM", "true",
+ "The device has random access memory">;
+
+// The device supports the `JMP k` and `CALL k` instructions.
+def FeatureJMPCALL : SubtargetFeature<"jmpcall", "m_hasJMPCALL", "true",
+ "The device supports the `JMP` and "
+ "`CALL` instructions">;
+
+
+// The device supports the indirect branches `IJMP` and `ICALL`.
+def FeatureIJMPCALL : SubtargetFeature<"ijmpcall", "m_hasIJMPCALL",
+ "true",
+ "The device supports `IJMP`/`ICALL`"
+ "instructions">;
+
+// The device supports the extended indirect branches `EIJMP` and `EICALL`.
+def FeatureEIJMPCALL : SubtargetFeature<"eijmpcall", "m_hasEIJMPCALL",
+ "true", "The device supports the "
+ "`EIJMP`/`EICALL` instructions">;
+
+// The device supports `ADDI Rd, K`, `SUBI Rd, K`.
+def FeatureADDSUBIW : SubtargetFeature<"addsubiw", "m_hasADDSUBIW",
+ "true", "Enable 16-bit register-immediate "
+ "addition and subtraction instructions">;
+
+// The device has an 8-bit stack pointer (SP) register.
+def FeatureSmallStack : SubtargetFeature<"smallstack", "m_hasSmallStack",
+ "true", "The device has an 8-bit "
+ "stack pointer">;
+
+// The device supports the 16-bit GPR pair MOVW instruction.
+def FeatureMOVW : SubtargetFeature<"movw", "m_hasMOVW", "true",
+ "The device supports the 16-bit MOVW "
+ "instruction">;
+
+// The device supports the `LPM` instruction, with implied destination being r0.
+def FeatureLPM : SubtargetFeature<"lpm", "m_hasLPM", "true",
+ "The device supports the `LPM` instruction">;
+
+// The device supports the `LPM Rd, Z[+] instruction.
+def FeatureLPMX : SubtargetFeature<"lpmx", "m_hasLPMX", "true",
+ "The device supports the `LPM Rd, Z[+]` "
+ "instruction">;
+
+// The device supports the `ELPM` instruction.
+def FeatureELPM : SubtargetFeature<"elpm", "m_hasELPM", "true",
+ "The device supports the ELPM instruction">;
+
+// The device supports the `ELPM Rd, Z[+]` instructions.
+def FeatureELPMX : SubtargetFeature<"elpmx", "m_hasELPMX", "true",
+ "The device supports the `ELPM Rd, Z[+]` "
+ "instructions">;
+
+// The device supports the `SPM` instruction.
+def FeatureSPM : SubtargetFeature<"spm", "m_hasSPM", "true",
+ "The device supports the `SPM` instruction">;
+
+// The device supports the `SPM Z+` instruction.
+def FeatureSPMX : SubtargetFeature<"spmx", "m_hasSPMX", "true",
+ "The device supports the `SPM Z+` "
+ "instruction">;
+
+// The device supports the `DES k` instruction.
+def FeatureDES : SubtargetFeature<"des", "m_hasDES", "true",
+ "The device supports the `DES k` encryption "
+ "instruction">;
+
+// The device supports the Read-Write-Modify instructions
+// XCH, LAS, LAC, and LAT.
+def FeatureRMW : SubtargetFeature<"rmw", "m_supportsRMW", "true",
+ "The device supports the read-write-modify "
+ "instructions: XCH, LAS, LAC, LAT">;
+
+// The device supports the `[F]MUL[S][U]` family of instructions.
+def FeatureMultiplication : SubtargetFeature<"mul", "m_supportsMultiplication",
+ "true", "The device supports the "
+ "multiplication instructions">;
+
+// The device supports the `BREAK` instruction.
+def FeatureBREAK : SubtargetFeature<"break", "m_hasBREAK", "true",
+ "The device supports the `BREAK` debugging "
+ "instruction">;
+
+// The device has instruction encodings specific to the Tiny core.
+def FeatureTinyEncoding : SubtargetFeature<"tinyencoding",
+ "m_hasTinyEncoding", "true",
+ "The device has Tiny core specific "
+ "instruction encodings">;
+
+class ELFArch<string name> : SubtargetFeature<"", "ELFArch",
+ !strconcat("ELF::",name), "">;
+
+// ELF e_flags architecture values
+def ELFArchAVR1 : ELFArch<"EF_AVR_ARCH_AVR1">;
+def ELFArchAVR2 : ELFArch<"EF_AVR_ARCH_AVR2">;
+def ELFArchAVR25 : ELFArch<"EF_AVR_ARCH_AVR25">;
+def ELFArchAVR3 : ELFArch<"EF_AVR_ARCH_AVR3">;
+def ELFArchAVR31 : ELFArch<"EF_AVR_ARCH_AVR31">;
+def ELFArchAVR35 : ELFArch<"EF_AVR_ARCH_AVR35">;
+def ELFArchAVR4 : ELFArch<"EF_AVR_ARCH_AVR4">;
+def ELFArchAVR5 : ELFArch<"EF_AVR_ARCH_AVR5">;
+def ELFArchAVR51 : ELFArch<"EF_AVR_ARCH_AVR51">;
+def ELFArchAVR6 : ELFArch<"EF_AVR_ARCH_AVR6">;
+def ELFArchAVRTiny : ELFArch<"EF_AVR_ARCH_AVRTINY">;
+def ELFArchXMEGA1 : ELFArch<"EF_AVR_ARCH_XMEGA1">;
+def ELFArchXMEGA2 : ELFArch<"EF_AVR_ARCH_XMEGA2">;
+def ELFArchXMEGA3 : ELFArch<"EF_AVR_ARCH_XMEGA3">;
+def ELFArchXMEGA4 : ELFArch<"EF_AVR_ARCH_XMEGA4">;
+def ELFArchXMEGA5 : ELFArch<"EF_AVR_ARCH_XMEGA5">;
+def ELFArchXMEGA6 : ELFArch<"EF_AVR_ARCH_XMEGA6">;
+def ELFArchXMEGA7 : ELFArch<"EF_AVR_ARCH_XMEGA7">;
+
+//===---------------------------------------------------------------------===//
+// AVR Families
+//===---------------------------------------------------------------------===//
+
+// The device has at least the bare minimum that **every** single AVR
+// device should have.
+def FamilyAVR0 : Family<"avr0", []>;
+
+def FamilyAVR1 : Family<"avr1", [FamilyAVR0, FeatureLPM]>;
+
+def FamilyAVR2 : Family<"avr2",
+ [FamilyAVR1, FeatureIJMPCALL, FeatureADDSUBIW,
+ FeatureSRAM]>;
+
+def FamilyAVR25 : Family<"avr25",
+ [FamilyAVR2, FeatureMOVW, FeatureLPMX,
+ FeatureSPM, FeatureBREAK]>;
+
+def FamilyAVR3 : Family<"avr3",
+ [FamilyAVR2, FeatureJMPCALL]>;
+
+def FamilyAVR31 : Family<"avr31",
+ [FamilyAVR3, FeatureELPM]>;
+
+def FamilyAVR35 : Family<"avr35",
+ [FamilyAVR3, FeatureMOVW, FeatureLPMX,
+ FeatureSPM, FeatureBREAK]>;
+
+def FamilyAVR4 : Family<"avr4",
+ [FamilyAVR2, FeatureMultiplication,
+ FeatureMOVW, FeatureLPMX, FeatureSPM,
+ FeatureBREAK]>;
+
+def FamilyAVR5 : Family<"avr5",
+ [FamilyAVR3, FeatureMultiplication,
+ FeatureMOVW, FeatureLPMX, FeatureSPM,
+ FeatureBREAK]>;
+
+def FamilyAVR51 : Family<"avr51",
+ [FamilyAVR5, FeatureELPM, FeatureELPMX]>;
+
+def FamilyAVR6 : Family<"avr6",
+ [FamilyAVR51]>;
+
+def FamilyAVRTiny : Family<"avrtiny",
+ [FamilyAVR0, FeatureBREAK, FeatureSRAM,
+ FeatureTinyEncoding]>;
+
+def FamilyXMEGA : Family<"xmega",
+ [FamilyAVR51, FeatureEIJMPCALL, FeatureSPMX,
+ FeatureDES]>;
+
+def FamilyXMEGAU : Family<"xmegau",
+ [FamilyXMEGA, FeatureRMW]>;
+
+def FeatureSetSpecial : FeatureSet<"special",
+ "Enable use of the entire instruction "
+ "set - used for debugging",
+ [FeatureSRAM, FeatureJMPCALL,
+ FeatureIJMPCALL, FeatureEIJMPCALL,
+ FeatureADDSUBIW, FeatureMOVW,
+ FeatureLPM, FeatureLPMX, FeatureELPM,
+ FeatureELPMX, FeatureSPM, FeatureSPMX,
+ FeatureDES, FeatureRMW,
+ FeatureMultiplication, FeatureBREAK]>;
+
+//===---------------------------------------------------------------------===//
+// AVR microcontrollers supported.
+//===---------------------------------------------------------------------===//
+
+class Device<string Name, Family Fam, ELFArch Arch,
+ list<SubtargetFeature> ExtraFeatures = []>
+ : Processor<Name, NoItineraries, !listconcat([Fam,Arch],ExtraFeatures)>;
+
+// Generic MCUs
+// Note that several versions of GCC has strange ELF architecture
+// settings for backwards compatibility - see `gas/config/tc-avr.c`
+// in AVR binutils. We do not replicate this.
+def : Device<"avr1", FamilyAVR1, ELFArchAVR1>;
+def : Device<"avr2", FamilyAVR2, ELFArchAVR2>;
+def : Device<"avr25", FamilyAVR25, ELFArchAVR25>;
+def : Device<"avr3", FamilyAVR3, ELFArchAVR3>;
+def : Device<"avr31", FamilyAVR31, ELFArchAVR31>;
+def : Device<"avr35", FamilyAVR35, ELFArchAVR35>;
+def : Device<"avr4", FamilyAVR4, ELFArchAVR4>;
+def : Device<"avr5", FamilyAVR5, ELFArchAVR5>;
+def : Device<"avr51", FamilyAVR51, ELFArchAVR51>;
+def : Device<"avr6", FamilyAVR6, ELFArchAVR6>;
+def : Device<"avrxmega1", FamilyXMEGA, ELFArchXMEGA1>;
+def : Device<"avrxmega2", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"avrxmega3", FamilyXMEGA, ELFArchXMEGA3>;
+def : Device<"avrxmega4", FamilyXMEGA, ELFArchXMEGA4>;
+def : Device<"avrxmega5", FamilyXMEGA, ELFArchXMEGA5>;
+def : Device<"avrxmega6", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"avrxmega7", FamilyXMEGA, ELFArchXMEGA7>;
+def : Device<"avrtiny", FamilyAVRTiny, ELFArchAVRTiny>;
+
+// Specific MCUs
+def : Device<"at90s1200", FamilyAVR0, ELFArchAVR1>;
+def : Device<"attiny11", FamilyAVR1, ELFArchAVR1>;
+def : Device<"attiny12", FamilyAVR1, ELFArchAVR1>;
+def : Device<"attiny15", FamilyAVR1, ELFArchAVR1>;
+def : Device<"attiny28", FamilyAVR1, ELFArchAVR1>;
+def : Device<"at90s2313", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s2323", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s2333", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s2343", FamilyAVR2, ELFArchAVR2>;
+def : Device<"attiny22", FamilyAVR2, ELFArchAVR2>;
+def : Device<"attiny26", FamilyAVR2, ELFArchAVR2, [FeatureLPMX]>;
+def : Device<"at86rf401", FamilyAVR2, ELFArchAVR25,
+ [FeatureMOVW, FeatureLPMX]>;
+def : Device<"at90s4414", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s4433", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s4434", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s8515", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90c8534", FamilyAVR2, ELFArchAVR2>;
+def : Device<"at90s8535", FamilyAVR2, ELFArchAVR2>;
+def : Device<"ata5272", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny13", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny13a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny2313", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny2313a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny24", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny24a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny4313", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny44", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny44a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny84", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny84a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny25", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny45", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny85", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny261", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny261a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny461", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny461a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny861", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny861a", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny87", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny43u", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny48", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny88", FamilyAVR25, ELFArchAVR25>;
+def : Device<"attiny828", FamilyAVR25, ELFArchAVR25>;
+def : Device<"at43usb355", FamilyAVR3, ELFArchAVR3>;
+def : Device<"at76c711", FamilyAVR3, ELFArchAVR3>;
+def : Device<"atmega103", FamilyAVR31, ELFArchAVR31>;
+def : Device<"at43usb320", FamilyAVR31, ELFArchAVR31>;
+def : Device<"attiny167", FamilyAVR35, ELFArchAVR35>;
+def : Device<"at90usb82", FamilyAVR35, ELFArchAVR35>;
+def : Device<"at90usb162", FamilyAVR35, ELFArchAVR35>;
+def : Device<"ata5505", FamilyAVR35, ELFArchAVR35>;
+def : Device<"atmega8u2", FamilyAVR35, ELFArchAVR35>;
+def : Device<"atmega16u2", FamilyAVR35, ELFArchAVR35>;
+def : Device<"atmega32u2", FamilyAVR35, ELFArchAVR35>;
+def : Device<"attiny1634", FamilyAVR35, ELFArchAVR35>;
+def : Device<"atmega8", FamilyAVR4, ELFArchAVR4>; // FIXME: family may be wrong
+def : Device<"ata6289", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega8a", FamilyAVR4, ELFArchAVR4>;
+def : Device<"ata6285", FamilyAVR4, ELFArchAVR4>;
+def : Device<"ata6286", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega48", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega48a", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega48pa", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega48p", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega88", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega88a", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega88p", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega88pa", FamilyAVR4, ELFArchAVR4>;
+def : Device<"atmega8515", FamilyAVR2, ELFArchAVR4,
+ [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
+def : Device<"atmega8535", FamilyAVR2, ELFArchAVR4,
+ [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
+def : Device<"atmega8hva", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm1", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm2", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm2b", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm3", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm3b", FamilyAVR4, ELFArchAVR4>;
+def : Device<"at90pwm81", FamilyAVR4, ELFArchAVR4>;
+def : Device<"ata5790", FamilyAVR5, ELFArchAVR5>;
+def : Device<"ata5795", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega161", FamilyAVR3, ELFArchAVR5,
+ [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
+def : Device<"atmega162", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega163", FamilyAVR3, ELFArchAVR5,
+ [FeatureMultiplication, FeatureMOVW, FeatureLPMX, FeatureSPM]>;
+def : Device<"atmega164a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega164p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega164pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega165", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega165a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega165p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega165pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega168", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega168a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega168p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega168pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega169", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega169a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega169p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega169pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega323", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega324a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega324p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega324pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega325", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega325a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega325p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega325pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3250", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3250a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3250p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3250pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega328", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega328p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega329", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega329a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega329p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega329pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3290", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3290a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3290p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega3290pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega406", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega640", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega644", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega644a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega644p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega644pa", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega645", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega645a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega645p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega649", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega649a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega649p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6450", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6450a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6450p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6490", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6490a", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega6490p", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64rfr2", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega644rfr2", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16hva", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16hva2", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16hvb", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16hvbrevb", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32hvb", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32hvbrevb", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64hve", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90can32", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90can64", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90pwm161", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90pwm216", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90pwm316", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32c1", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64c1", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16m1", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32m1", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega64m1", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega16u4", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32u4", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega32u6", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90usb646", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90usb647", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at90scr100", FamilyAVR5, ELFArchAVR5>;
+def : Device<"at94k", FamilyAVR3, ELFArchAVR5,
+ [FeatureMultiplication, FeatureMOVW, FeatureLPMX]>;
+def : Device<"m3000", FamilyAVR5, ELFArchAVR5>;
+def : Device<"atmega128", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega128a", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega1280", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega1281", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega1284", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega1284p", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega128rfa1", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega128rfr2", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega1284rfr2", FamilyAVR51, ELFArchAVR51>;
+def : Device<"at90can128", FamilyAVR51, ELFArchAVR51>;
+def : Device<"at90usb1286", FamilyAVR51, ELFArchAVR51>;
+def : Device<"at90usb1287", FamilyAVR51, ELFArchAVR51>;
+def : Device<"atmega2560", FamilyAVR6, ELFArchAVR6>;
+def : Device<"atmega2561", FamilyAVR6, ELFArchAVR6>;
+def : Device<"atmega256rfr2", FamilyAVR6, ELFArchAVR6>;
+def : Device<"atmega2564rfr2", FamilyAVR6, ELFArchAVR6>;
+def : Device<"atxmega16a4", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega16a4u", FamilyXMEGAU, ELFArchXMEGA2>;
+def : Device<"atxmega16c4", FamilyXMEGAU, ELFArchXMEGA2>;
+def : Device<"atxmega16d4", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega32a4", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega32a4u", FamilyXMEGAU, ELFArchXMEGA2>;
+def : Device<"atxmega32c4", FamilyXMEGAU, ELFArchXMEGA2>;
+def : Device<"atxmega32d4", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega32e5", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega16e5", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega8e5", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega32x1", FamilyXMEGA, ELFArchXMEGA2>;
+def : Device<"atxmega64a3", FamilyXMEGA, ELFArchXMEGA4>;
+def : Device<"atxmega64a3u", FamilyXMEGAU, ELFArchXMEGA4>;
+def : Device<"atxmega64a4u", FamilyXMEGAU, ELFArchXMEGA4>;
+def : Device<"atxmega64b1", FamilyXMEGAU, ELFArchXMEGA4>;
+def : Device<"atxmega64b3", FamilyXMEGAU, ELFArchXMEGA4>;
+def : Device<"atxmega64c3", FamilyXMEGAU, ELFArchXMEGA4>;
+def : Device<"atxmega64d3", FamilyXMEGA, ELFArchXMEGA4>;
+def : Device<"atxmega64d4", FamilyXMEGA, ELFArchXMEGA4>;
+def : Device<"atxmega64a1", FamilyXMEGA, ELFArchXMEGA5>;
+def : Device<"atxmega64a1u", FamilyXMEGAU, ELFArchXMEGA5>;
+def : Device<"atxmega128a3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega128a3u", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega128b1", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega128b3", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega128c3", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega128d3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega128d4", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega192a3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega192a3u", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega192c3", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega192d3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega256a3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega256a3u", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega256a3b", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega256a3bu", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega256c3", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega256d3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega384c3", FamilyXMEGAU, ELFArchXMEGA6>;
+def : Device<"atxmega384d3", FamilyXMEGA, ELFArchXMEGA6>;
+def : Device<"atxmega128a1", FamilyXMEGA, ELFArchXMEGA7>;
+def : Device<"atxmega128a1u", FamilyXMEGAU, ELFArchXMEGA7>;
+def : Device<"atxmega128a4u", FamilyXMEGAU, ELFArchXMEGA7>;
+def : Device<"attiny4", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny5", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny9", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny10", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny20", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny40", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny102", FamilyAVRTiny, ELFArchAVRTiny>;
+def : Device<"attiny104", FamilyAVRTiny, ELFArchAVRTiny>;
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/contrib/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
new file mode 100644
index 0000000..1b2f2ce
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
@@ -0,0 +1,1515 @@
+//===-- AVRExpandPseudoInsts.cpp - Expand pseudo instructions -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a pass that expands pseudo instructions into target
+// instructions. This pass should be run after register allocation but before
+// the post-regalloc scheduling pass.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRInstrInfo.h"
+#include "AVRTargetMachine.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/RegisterScavenging.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+
+using namespace llvm;
+
+#define AVR_EXPAND_PSEUDO_NAME "AVR pseudo instruction expansion pass"
+
+namespace {
+
+/// Expands "placeholder" instructions marked as pseudo into
+/// actual AVR instructions.
+class AVRExpandPseudo : public MachineFunctionPass {
+public:
+ static char ID;
+
+ AVRExpandPseudo() : MachineFunctionPass(ID) {
+ initializeAVRExpandPseudoPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ StringRef getPassName() const override { return AVR_EXPAND_PSEUDO_NAME; }
+
+private:
+ typedef MachineBasicBlock Block;
+ typedef Block::iterator BlockIt;
+
+ const AVRRegisterInfo *TRI;
+ const TargetInstrInfo *TII;
+
+ /// The register to be used for temporary storage.
+ const unsigned SCRATCH_REGISTER = AVR::R0;
+ /// The IO address of the status register.
+ const unsigned SREG_ADDR = 0x3f;
+
+ bool expandMBB(Block &MBB);
+ bool expandMI(Block &MBB, BlockIt MBBI);
+ template <unsigned OP> bool expand(Block &MBB, BlockIt MBBI);
+
+ MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned Opcode) {
+ return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode));
+ }
+
+ MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned Opcode,
+ unsigned DstReg) {
+ return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode), DstReg);
+ }
+
+ MachineRegisterInfo &getRegInfo(Block &MBB) { return MBB.getParent()->getRegInfo(); }
+
+ bool expandArith(unsigned OpLo, unsigned OpHi, Block &MBB, BlockIt MBBI);
+ bool expandLogic(unsigned Op, Block &MBB, BlockIt MBBI);
+ bool expandLogicImm(unsigned Op, Block &MBB, BlockIt MBBI);
+ bool isLogicImmOpRedundant(unsigned Op, unsigned ImmVal) const;
+
+ template<typename Func>
+ bool expandAtomic(Block &MBB, BlockIt MBBI, Func f);
+
+ template<typename Func>
+ bool expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI, Func f);
+
+ bool expandAtomicBinaryOp(unsigned Opcode, Block &MBB, BlockIt MBBI);
+
+ bool expandAtomicArithmeticOp(unsigned MemOpcode,
+ unsigned ArithOpcode,
+ Block &MBB,
+ BlockIt MBBI);
+};
+
+char AVRExpandPseudo::ID = 0;
+
+bool AVRExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
+ bool Modified = false;
+
+ BlockIt MBBI = MBB.begin(), E = MBB.end();
+ while (MBBI != E) {
+ BlockIt NMBBI = std::next(MBBI);
+ Modified |= expandMI(MBB, MBBI);
+ MBBI = NMBBI;
+ }
+
+ return Modified;
+}
+
+bool AVRExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
+ bool Modified = false;
+
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ TRI = STI.getRegisterInfo();
+ TII = STI.getInstrInfo();
+
+ // We need to track liveness in order to use register scavenging.
+ MF.getProperties().set(MachineFunctionProperties::Property::TracksLiveness);
+
+ for (Block &MBB : MF) {
+ bool ContinueExpanding = true;
+ unsigned ExpandCount = 0;
+
+ // Continue expanding the block until all pseudos are expanded.
+ do {
+ assert(ExpandCount < 10 && "pseudo expand limit reached");
+
+ bool BlockModified = expandMBB(MBB);
+ Modified |= BlockModified;
+ ExpandCount++;
+
+ ContinueExpanding = BlockModified;
+ } while (ContinueExpanding);
+ }
+
+ return Modified;
+}
+
+bool AVRExpandPseudo::
+expandArith(unsigned OpLo, unsigned OpHi, Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(4).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+bool AVRExpandPseudo::
+expandLogic(unsigned Op, Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, Op)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ // SREG is always implicitly dead
+ MIBLO->getOperand(3).setIsDead();
+
+ auto MIBHI = buildMI(MBB, MBBI, Op)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+bool AVRExpandPseudo::
+ isLogicImmOpRedundant(unsigned Op, unsigned ImmVal) const {
+
+ // ANDI Rd, 0xff is redundant.
+ if (Op == AVR::ANDIRdK && ImmVal == 0xff)
+ return true;
+
+ // ORI Rd, 0x0 is redundant.
+ if (Op == AVR::ORIRdK && ImmVal == 0x0)
+ return true;
+
+ return false;
+}
+
+bool AVRExpandPseudo::
+expandLogicImm(unsigned Op, Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ unsigned Imm = MI.getOperand(2).getImm();
+ unsigned Lo8 = Imm & 0xff;
+ unsigned Hi8 = (Imm >> 8) & 0xff;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ if (!isLogicImmOpRedundant(Op, Lo8)) {
+ auto MIBLO = buildMI(MBB, MBBI, Op)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(SrcIsKill))
+ .addImm(Lo8);
+
+ // SREG is always implicitly dead
+ MIBLO->getOperand(3).setIsDead();
+ }
+
+ if (!isLogicImmOpRedundant(Op, Hi8)) {
+ auto MIBHI = buildMI(MBB, MBBI, Op)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(SrcIsKill))
+ .addImm(Hi8);
+
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+ }
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ADDWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandArith(AVR::ADDRdRr, AVR::ADCRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ADCWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandArith(AVR::ADCRdRr, AVR::ADCRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SUBWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandArith(AVR::SUBRdRr, AVR::SBCRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SUBIWRdK>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, AVR::SUBIRdK)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(SrcIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, AVR::SBCIRdK)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(SrcIsKill));
+
+ switch (MI.getOperand(2).getType()) {
+ case MachineOperand::MO_GlobalAddress: {
+ const GlobalValue *GV = MI.getOperand(2).getGlobal();
+ int64_t Offs = MI.getOperand(2).getOffset();
+ unsigned TF = MI.getOperand(2).getTargetFlags();
+ MIBLO.addGlobalAddress(GV, Offs, TF | AVRII::MO_NEG | AVRII::MO_LO);
+ MIBHI.addGlobalAddress(GV, Offs, TF | AVRII::MO_NEG | AVRII::MO_HI);
+ break;
+ }
+ case MachineOperand::MO_Immediate: {
+ unsigned Imm = MI.getOperand(2).getImm();
+ MIBLO.addImm(Imm & 0xff);
+ MIBHI.addImm((Imm >> 8) & 0xff);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown operand type!");
+ }
+
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(4).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SBCWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandArith(AVR::SBCRdRr, AVR::SBCRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SBCIWRdK>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(3).isDead();
+ unsigned Imm = MI.getOperand(2).getImm();
+ unsigned Lo8 = Imm & 0xff;
+ unsigned Hi8 = (Imm >> 8) & 0xff;
+ OpLo = AVR::SBCIRdK;
+ OpHi = AVR::SBCIRdK;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(SrcIsKill))
+ .addImm(Lo8);
+
+ // SREG is always implicitly killed
+ MIBLO->getOperand(4).setIsKill();
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(SrcIsKill))
+ .addImm(Hi8);
+
+ if (ImpIsDead)
+ MIBHI->getOperand(3).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(4).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ANDWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandLogic(AVR::ANDRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ANDIWRdK>(Block &MBB, BlockIt MBBI) {
+ return expandLogicImm(AVR::ANDIRdK, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ORWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandLogic(AVR::ORRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ORIWRdK>(Block &MBB, BlockIt MBBI) {
+ return expandLogicImm(AVR::ORIRdK, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::EORWRdRr>(Block &MBB, BlockIt MBBI) {
+ return expandLogic(AVR::EORRdRr, MBB, MBBI);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::COMWRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::COMRd;
+ OpHi = AVR::COMRd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ // SREG is always implicitly dead
+ MIBLO->getOperand(2).setIsDead();
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(2).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::CPWRdRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsKill = MI.getOperand(0).isKill();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::CPRdRr;
+ OpHi = AVR::CPCRdRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // Low part
+ buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(2).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(3).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::CPCWRdRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsKill = MI.getOperand(0).isKill();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::CPCRdRr;
+ OpHi = AVR::CPCRdRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, getKillRegState(DstIsKill))
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ // SREG is always implicitly killed
+ MIBLO->getOperand(3).setIsKill();
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(2).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(3).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDIWRdK>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ OpLo = AVR::LDIRdK;
+ OpHi = AVR::LDIRdK;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead));
+
+ switch (MI.getOperand(1).getType()) {
+ case MachineOperand::MO_GlobalAddress: {
+ const GlobalValue *GV = MI.getOperand(1).getGlobal();
+ int64_t Offs = MI.getOperand(1).getOffset();
+ unsigned TF = MI.getOperand(1).getTargetFlags();
+
+ MIBLO.addGlobalAddress(GV, Offs, TF | AVRII::MO_LO);
+ MIBHI.addGlobalAddress(GV, Offs, TF | AVRII::MO_HI);
+ break;
+ }
+ case MachineOperand::MO_BlockAddress: {
+ const BlockAddress *BA = MI.getOperand(1).getBlockAddress();
+ unsigned TF = MI.getOperand(1).getTargetFlags();
+
+ MIBLO.addOperand(MachineOperand::CreateBA(BA, TF | AVRII::MO_LO));
+ MIBHI.addOperand(MachineOperand::CreateBA(BA, TF | AVRII::MO_HI));
+ break;
+ }
+ case MachineOperand::MO_Immediate: {
+ unsigned Imm = MI.getOperand(1).getImm();
+
+ MIBLO.addImm(Imm & 0xff);
+ MIBHI.addImm((Imm >> 8) & 0xff);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown operand type!");
+ }
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDSWRdK>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ OpLo = AVR::LDSRdK;
+ OpHi = AVR::LDSRdK;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead));
+
+ switch (MI.getOperand(1).getType()) {
+ case MachineOperand::MO_GlobalAddress: {
+ const GlobalValue *GV = MI.getOperand(1).getGlobal();
+ int64_t Offs = MI.getOperand(1).getOffset();
+ unsigned TF = MI.getOperand(1).getTargetFlags();
+
+ MIBLO.addGlobalAddress(GV, Offs, TF);
+ MIBHI.addGlobalAddress(GV, Offs + 1, TF);
+ break;
+ }
+ case MachineOperand::MO_Immediate: {
+ unsigned Imm = MI.getOperand(1).getImm();
+
+ MIBLO.addImm(Imm);
+ MIBHI.addImm(Imm + 1);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown operand type!");
+ }
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDWRdPtr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ OpLo = AVR::LDRdPtr;
+ OpHi = AVR::LDDRdPtrQ;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg);
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, getKillRegState(SrcIsKill))
+ .addImm(1);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDWRdPtrPi>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsDead = MI.getOperand(1).isKill();
+ OpLo = AVR::LDRdPtrPi;
+ OpHi = AVR::LDRdPtrPi;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, RegState::Define)
+ .addReg(SrcReg, RegState::Kill);
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, RegState::Define | getDeadRegState(SrcIsDead))
+ .addReg(SrcReg, RegState::Kill);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDWRdPtrPd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsDead = MI.getOperand(1).isKill();
+ OpLo = AVR::LDRdPtrPd;
+ OpHi = AVR::LDRdPtrPd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, RegState::Define)
+ .addReg(SrcReg, RegState::Kill);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, RegState::Define | getDeadRegState(SrcIsDead))
+ .addReg(SrcReg, RegState::Kill);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ unsigned Imm = MI.getOperand(2).getImm();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ OpLo = AVR::LDDRdPtrQ;
+ OpHi = AVR::LDDRdPtrQ;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ assert(Imm <= 63 && "Offset is out of range");
+
+ MachineInstr *MIBLO, *MIBHI;
+
+ // HACK: We shouldn't have instances of this instruction
+ // where src==dest because the instruction itself is
+ // marked earlyclobber. We do however get this instruction when
+ // loading from stack slots where the earlyclobber isn't useful.
+ //
+ // In this case, just use a temporary register.
+ if (DstReg == SrcReg) {
+ RegScavenger RS;
+
+ RS.enterBasicBlock(MBB);
+ RS.forward(MBBI);
+
+ BitVector Candidates =
+ TRI->getAllocatableSet
+ (*MBB.getParent(), &AVR::GPR8RegClass);
+
+ // Exclude all the registers being used by the instruction.
+ for (MachineOperand &MO : MI.operands()) {
+ if (MO.isReg() && MO.getReg() != 0 && !MO.isDef() &&
+ !TargetRegisterInfo::isVirtualRegister(MO.getReg()))
+ Candidates.reset(MO.getReg());
+ }
+
+ BitVector Available = RS.getRegsAvailable(&AVR::GPR8RegClass);
+ Available &= Candidates;
+
+ signed TmpReg = Available.find_first();
+ assert(TmpReg != -1 && "ran out of registers");
+
+ MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(TmpReg, RegState::Define)
+ .addReg(SrcReg)
+ .addImm(Imm);
+
+ buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstLoReg).addReg(TmpReg);
+
+ MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(TmpReg, RegState::Define)
+ .addReg(SrcReg, getKillRegState(SrcIsKill))
+ .addImm(Imm + 1);
+
+ buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg);
+ } else {
+ MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg)
+ .addImm(Imm);
+
+ MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, getKillRegState(SrcIsKill))
+ .addImm(Imm + 1);
+ }
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LPMWRdZ>(Block &MBB, BlockIt MBBI) {
+ llvm_unreachable("wide LPM is unimplemented");
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LPMWRdZPi>(Block &MBB, BlockIt MBBI) {
+ llvm_unreachable("wide LPMPi is unimplemented");
+}
+
+template<typename Func>
+bool AVRExpandPseudo::expandAtomic(Block &MBB, BlockIt MBBI, Func f) {
+ // Remove the pseudo instruction.
+ MachineInstr &MI = *MBBI;
+
+ // Store the SREG.
+ buildMI(MBB, MBBI, AVR::INRdA)
+ .addReg(SCRATCH_REGISTER, RegState::Define)
+ .addImm(SREG_ADDR);
+
+ // Disable exceptions.
+ buildMI(MBB, MBBI, AVR::BCLRs).addImm(7); // CLI
+
+ f(MI);
+
+ // Restore the status reg.
+ buildMI(MBB, MBBI, AVR::OUTARr)
+ .addImm(SREG_ADDR)
+ .addReg(SCRATCH_REGISTER);
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template<typename Func>
+bool AVRExpandPseudo::expandAtomicBinaryOp(unsigned Opcode,
+ Block &MBB,
+ BlockIt MBBI,
+ Func f) {
+ return expandAtomic(MBB, MBBI, [&](MachineInstr &MI) {
+ auto Op1 = MI.getOperand(0);
+ auto Op2 = MI.getOperand(1);
+
+ MachineInstr &NewInst = *buildMI(MBB, MBBI, Opcode)
+ .addOperand(Op1).addOperand(Op2)
+ .getInstr();
+ f(NewInst);
+ });
+}
+
+bool AVRExpandPseudo::expandAtomicBinaryOp(unsigned Opcode,
+ Block &MBB,
+ BlockIt MBBI) {
+ return expandAtomicBinaryOp(Opcode, MBB, MBBI, [](MachineInstr &MI) {});
+}
+
+bool AVRExpandPseudo::expandAtomicArithmeticOp(unsigned Width,
+ unsigned ArithOpcode,
+ Block &MBB,
+ BlockIt MBBI) {
+ return expandAtomic(MBB, MBBI, [&](MachineInstr &MI) {
+ auto Op1 = MI.getOperand(0);
+ auto Op2 = MI.getOperand(1);
+
+ unsigned LoadOpcode = (Width == 8) ? AVR::LDRdPtr : AVR::LDWRdPtr;
+ unsigned StoreOpcode = (Width == 8) ? AVR::STPtrRr : AVR::STWPtrRr;
+
+ // Create the load
+ buildMI(MBB, MBBI, LoadOpcode).addOperand(Op1).addOperand(Op2);
+
+ // Create the arithmetic op
+ buildMI(MBB, MBBI, ArithOpcode)
+ .addOperand(Op1).addOperand(Op1)
+ .addOperand(Op2);
+
+ // Create the store
+ buildMI(MBB, MBBI, StoreOpcode).addOperand(Op2).addOperand(Op1);
+ });
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoad8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicBinaryOp(AVR::LDRdPtr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoad16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicBinaryOp(AVR::LDWRdPtr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicStore8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicBinaryOp(AVR::STPtrRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicStore16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicBinaryOp(AVR::STWPtrRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadAdd8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(8, AVR::ADDRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadAdd16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(16, AVR::ADDWRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadSub8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(8, AVR::SUBRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadSub16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(16, AVR::SUBWRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadAnd8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(8, AVR::ANDRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadAnd16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(16, AVR::ANDWRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadOr8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(8, AVR::ORRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadOr16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(16, AVR::ORWRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadXor8>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(8, AVR::EORRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicLoadXor16>(Block &MBB, BlockIt MBBI) {
+ return expandAtomicArithmeticOp(16, AVR::EORWRdRr, MBB, MBBI);
+}
+
+template<>
+bool AVRExpandPseudo::expand<AVR::AtomicFence>(Block &MBB, BlockIt MBBI) {
+ // On AVR, there is only one core and so atomic fences do nothing.
+ MBBI->eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::STSWKRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ OpLo = AVR::STSKRr;
+ OpHi = AVR::STSKRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ // Write the high byte first in case this address belongs to a special
+ // I/O address with a special temporary register.
+ auto MIBHI = buildMI(MBB, MBBI, OpHi);
+ auto MIBLO = buildMI(MBB, MBBI, OpLo);
+
+ switch (MI.getOperand(0).getType()) {
+ case MachineOperand::MO_GlobalAddress: {
+ const GlobalValue *GV = MI.getOperand(0).getGlobal();
+ int64_t Offs = MI.getOperand(0).getOffset();
+ unsigned TF = MI.getOperand(0).getTargetFlags();
+
+ MIBLO.addGlobalAddress(GV, Offs, TF);
+ MIBHI.addGlobalAddress(GV, Offs + 1, TF);
+ break;
+ }
+ case MachineOperand::MO_Immediate: {
+ unsigned Imm = MI.getOperand(0).getImm();
+
+ MIBLO.addImm(Imm);
+ MIBHI.addImm(Imm + 1);
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown operand type!");
+ }
+
+ MIBLO.addReg(SrcLoReg, getKillRegState(SrcIsKill));
+ MIBHI.addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::STWPtrRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsKill = MI.getOperand(0).isKill();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ OpLo = AVR::STPtrRr;
+ OpHi = AVR::STDPtrQRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ //:TODO: need to reverse this order like inw and stsw?
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstReg)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstReg, getKillRegState(DstIsKill))
+ .addImm(1)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::STWPtrPiRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ unsigned Imm = MI.getOperand(3).getImm();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+ OpLo = AVR::STPtrPiRr;
+ OpHi = AVR::STPtrPiRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstReg, RegState::Define)
+ .addReg(DstReg, RegState::Kill)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill))
+ .addImm(Imm);
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstReg, RegState::Kill)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill))
+ .addImm(Imm);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::STWPtrPdRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ unsigned Imm = MI.getOperand(3).getImm();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+ OpLo = AVR::STPtrPdRr;
+ OpHi = AVR::STPtrPdRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ assert(DstReg != SrcReg && "SrcReg and DstReg cannot be the same");
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstReg, RegState::Define)
+ .addReg(DstReg, RegState::Kill)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill))
+ .addImm(Imm);
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstReg, RegState::Kill)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill))
+ .addImm(Imm);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ unsigned Imm = MI.getOperand(1).getImm();
+ bool DstIsKill = MI.getOperand(0).isKill();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+ OpLo = AVR::STDPtrQRr;
+ OpHi = AVR::STDPtrQRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ assert(Imm <= 63 && "Offset is out of range");
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstReg)
+ .addImm(Imm)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstReg, getKillRegState(DstIsKill))
+ .addImm(Imm + 1)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::INWRdA>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned Imm = MI.getOperand(1).getImm();
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ OpLo = AVR::INRdA;
+ OpHi = AVR::INRdA;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ assert(Imm <= 63 && "Address is out of range");
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addImm(Imm);
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addImm(Imm + 1);
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::OUTWARr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned Imm = MI.getOperand(0).getImm();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ OpLo = AVR::OUTARr;
+ OpHi = AVR::OUTARr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ assert(Imm <= 63 && "Address is out of range");
+
+ // 16 bit I/O writes need the high byte first
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addImm(Imm + 1)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill));
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addImm(Imm)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill));
+
+ MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+ MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::PUSHWRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, SrcLoReg, SrcHiReg;
+ unsigned SrcReg = MI.getOperand(0).getReg();
+ bool SrcIsKill = MI.getOperand(0).isKill();
+ unsigned Flags = MI.getFlags();
+ OpLo = AVR::PUSHRr;
+ OpHi = AVR::PUSHRr;
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ // Low part
+ buildMI(MBB, MBBI, OpLo)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill))
+ .setMIFlags(Flags);
+
+ // High part
+ buildMI(MBB, MBBI, OpHi)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill))
+ .setMIFlags(Flags);
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::POPWRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned Flags = MI.getFlags();
+ OpLo = AVR::POPRd;
+ OpHi = AVR::POPRd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ buildMI(MBB, MBBI, OpHi, DstHiReg).setMIFlags(Flags); // High
+ buildMI(MBB, MBBI, OpLo, DstLoReg).setMIFlags(Flags); // Low
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LSLWRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::LSLRd;
+ OpHi = AVR::ROLRd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // Low part
+ buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ auto MIBHI = buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MIBHI->getOperand(2).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBHI->getOperand(3).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::RORRd;
+ OpHi = AVR::LSRRd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // High part
+ buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MIBLO->getOperand(2).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBLO->getOperand(3).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::RORWRd>(Block &MBB, BlockIt MBBI) {
+ llvm_unreachable("RORW unimplemented");
+ return false;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ROLWRd>(Block &MBB, BlockIt MBBI) {
+ llvm_unreachable("ROLW unimplemented");
+ return false;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ASRWRd>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ OpLo = AVR::RORRd;
+ OpHi = AVR::ASRRd;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // High part
+ buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ auto MIBLO = buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MIBLO->getOperand(2).setIsDead();
+
+ // SREG is always implicitly killed
+ MIBLO->getOperand(3).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <> bool AVRExpandPseudo::expand<AVR::SEXT>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned DstLoReg, DstHiReg;
+ // sext R17:R16, R17
+ // mov r16, r17
+ // lsl r17
+ // sbc r17, r17
+ // sext R17:R16, R13
+ // mov r16, r13
+ // mov r17, r13
+ // lsl r17
+ // sbc r17, r17
+ // sext R17:R16, R16
+ // mov r17, r16
+ // lsl r17
+ // sbc r17, r17
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ if (SrcReg != DstLoReg) {
+ auto MOV = buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg);
+
+ if (SrcReg == DstHiReg) {
+ MOV->getOperand(1).setIsKill();
+ }
+ }
+
+ if (SrcReg != DstHiReg) {
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstHiReg, RegState::Define)
+ .addReg(SrcReg, getKillRegState(SrcIsKill));
+ }
+
+ buildMI(MBB, MBBI, AVR::LSLRd)
+ .addReg(DstHiReg, RegState::Define)
+ .addReg(DstHiReg, RegState::Kill);
+
+ auto SBC = buildMI(MBB, MBBI, AVR::SBCRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, RegState::Kill)
+ .addReg(DstHiReg, RegState::Kill);
+
+ if (ImpIsDead)
+ SBC->getOperand(3).setIsDead();
+
+ // SREG is always implicitly killed
+ SBC->getOperand(4).setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <> bool AVRExpandPseudo::expand<AVR::ZEXT>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned DstLoReg, DstHiReg;
+ // zext R25:R24, R20
+ // mov R24, R20
+ // eor R25, R25
+ // zext R25:R24, R24
+ // eor R25, R25
+ // zext R25:R24, R25
+ // mov R24, R25
+ // eor R25, R25
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ bool ImpIsDead = MI.getOperand(2).isDead();
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ if (SrcReg != DstLoReg) {
+ buildMI(MBB, MBBI, AVR::MOVRdRr)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(SrcReg, getKillRegState(SrcIsKill));
+ }
+
+ auto EOR = buildMI(MBB, MBBI, AVR::EORRdRr)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, RegState::Kill)
+ .addReg(DstHiReg, RegState::Kill);
+
+ if (ImpIsDead)
+ EOR->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SPREAD>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned OpLo, OpHi, DstLoReg, DstHiReg;
+ unsigned DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ unsigned Flags = MI.getFlags();
+ OpLo = AVR::INRdA;
+ OpHi = AVR::INRdA;
+ TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+ // Low part
+ buildMI(MBB, MBBI, OpLo)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addImm(0x3d)
+ .setMIFlags(Flags);
+
+ // High part
+ buildMI(MBB, MBBI, OpHi)
+ .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addImm(0x3e)
+ .setMIFlags(Flags);
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::SPWRITE>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ unsigned SrcLoReg, SrcHiReg;
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ unsigned Flags = MI.getFlags();
+ TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
+
+ buildMI(MBB, MBBI, AVR::INRdA)
+ .addReg(AVR::R0, RegState::Define)
+ .addImm(SREG_ADDR)
+ .setMIFlags(Flags);
+
+ buildMI(MBB, MBBI, AVR::BCLRs).addImm(0x07).setMIFlags(Flags);
+
+ buildMI(MBB, MBBI, AVR::OUTARr)
+ .addImm(0x3e)
+ .addReg(SrcHiReg, getKillRegState(SrcIsKill))
+ .setMIFlags(Flags);
+
+ buildMI(MBB, MBBI, AVR::OUTARr)
+ .addImm(SREG_ADDR)
+ .addReg(AVR::R0, RegState::Kill)
+ .setMIFlags(Flags);
+
+ buildMI(MBB, MBBI, AVR::OUTARr)
+ .addImm(0x3d)
+ .addReg(SrcLoReg, getKillRegState(SrcIsKill))
+ .setMIFlags(Flags);
+
+ MI.eraseFromParent();
+ return true;
+}
+
+bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ int Opcode = MBBI->getOpcode();
+
+#define EXPAND(Op) \
+ case Op: \
+ return expand<Op>(MBB, MI)
+
+ switch (Opcode) {
+ EXPAND(AVR::ADDWRdRr);
+ EXPAND(AVR::ADCWRdRr);
+ EXPAND(AVR::SUBWRdRr);
+ EXPAND(AVR::SUBIWRdK);
+ EXPAND(AVR::SBCWRdRr);
+ EXPAND(AVR::SBCIWRdK);
+ EXPAND(AVR::ANDWRdRr);
+ EXPAND(AVR::ANDIWRdK);
+ EXPAND(AVR::ORWRdRr);
+ EXPAND(AVR::ORIWRdK);
+ EXPAND(AVR::EORWRdRr);
+ EXPAND(AVR::COMWRd);
+ EXPAND(AVR::CPWRdRr);
+ EXPAND(AVR::CPCWRdRr);
+ EXPAND(AVR::LDIWRdK);
+ EXPAND(AVR::LDSWRdK);
+ EXPAND(AVR::LDWRdPtr);
+ EXPAND(AVR::LDWRdPtrPi);
+ EXPAND(AVR::LDWRdPtrPd);
+ case AVR::LDDWRdYQ: //:FIXME: remove this once PR13375 gets fixed
+ EXPAND(AVR::LDDWRdPtrQ);
+ EXPAND(AVR::LPMWRdZ);
+ EXPAND(AVR::LPMWRdZPi);
+ EXPAND(AVR::AtomicLoad8);
+ EXPAND(AVR::AtomicLoad16);
+ EXPAND(AVR::AtomicStore8);
+ EXPAND(AVR::AtomicStore16);
+ EXPAND(AVR::AtomicLoadAdd8);
+ EXPAND(AVR::AtomicLoadAdd16);
+ EXPAND(AVR::AtomicLoadSub8);
+ EXPAND(AVR::AtomicLoadSub16);
+ EXPAND(AVR::AtomicLoadAnd8);
+ EXPAND(AVR::AtomicLoadAnd16);
+ EXPAND(AVR::AtomicLoadOr8);
+ EXPAND(AVR::AtomicLoadOr16);
+ EXPAND(AVR::AtomicLoadXor8);
+ EXPAND(AVR::AtomicLoadXor16);
+ EXPAND(AVR::AtomicFence);
+ EXPAND(AVR::STSWKRr);
+ EXPAND(AVR::STWPtrRr);
+ EXPAND(AVR::STWPtrPiRr);
+ EXPAND(AVR::STWPtrPdRr);
+ EXPAND(AVR::STDWPtrQRr);
+ EXPAND(AVR::INWRdA);
+ EXPAND(AVR::OUTWARr);
+ EXPAND(AVR::PUSHWRr);
+ EXPAND(AVR::POPWRd);
+ EXPAND(AVR::LSLWRd);
+ EXPAND(AVR::LSRWRd);
+ EXPAND(AVR::RORWRd);
+ EXPAND(AVR::ROLWRd);
+ EXPAND(AVR::ASRWRd);
+ EXPAND(AVR::SEXT);
+ EXPAND(AVR::ZEXT);
+ EXPAND(AVR::SPREAD);
+ EXPAND(AVR::SPWRITE);
+ }
+#undef EXPAND
+ return false;
+}
+
+} // end of anonymous namespace
+
+INITIALIZE_PASS(AVRExpandPseudo, "avr-expand-pseudo",
+ AVR_EXPAND_PSEUDO_NAME, false, false)
+namespace llvm {
+
+FunctionPass *createAVRExpandPseudoPass() { return new AVRExpandPseudo(); }
+
+} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRFrameLowering.cpp b/contrib/llvm/lib/Target/AVR/AVRFrameLowering.cpp
new file mode 100644
index 0000000..b8cb221
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRFrameLowering.cpp
@@ -0,0 +1,538 @@
+//===-- AVRFrameLowering.cpp - AVR Frame Information ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the AVR implementation of TargetFrameLowering class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRFrameLowering.h"
+
+#include "AVR.h"
+#include "AVRInstrInfo.h"
+#include "AVRMachineFunctionInfo.h"
+#include "AVRTargetMachine.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Function.h"
+
+#include <vector>
+
+namespace llvm {
+
+AVRFrameLowering::AVRFrameLowering()
+ : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 1, -2) {}
+
+bool AVRFrameLowering::canSimplifyCallFramePseudos(
+ const MachineFunction &MF) const {
+ // Always simplify call frame pseudo instructions, even when
+ // hasReservedCallFrame is false.
+ return true;
+}
+
+bool AVRFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
+ // Reserve call frame memory in function prologue under the following
+ // conditions:
+ // - Y pointer is reserved to be the frame pointer.
+ // - The function does not contain variable sized objects.
+
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ return hasFP(MF) && !MFI.hasVarSizedObjects();
+}
+
+void AVRFrameLowering::emitPrologue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ MachineBasicBlock::iterator MBBI = MBB.begin();
+ CallingConv::ID CallConv = MF.getFunction()->getCallingConv();
+ DebugLoc DL = (MBBI != MBB.end()) ? MBBI->getDebugLoc() : DebugLoc();
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const AVRInstrInfo &TII = *STI.getInstrInfo();
+
+ // Interrupt handlers re-enable interrupts in function entry.
+ if (CallConv == CallingConv::AVR_INTR) {
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::BSETs))
+ .addImm(0x07)
+ .setMIFlag(MachineInstr::FrameSetup);
+ }
+
+ // Emit special prologue code to save R1, R0 and SREG in interrupt/signal
+ // handlers before saving any other registers.
+ if (CallConv == CallingConv::AVR_INTR ||
+ CallConv == CallingConv::AVR_SIGNAL) {
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHWRr))
+ .addReg(AVR::R1R0, RegState::Kill)
+ .setMIFlag(MachineInstr::FrameSetup);
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::INRdA), AVR::R0)
+ .addImm(0x3f)
+ .setMIFlag(MachineInstr::FrameSetup);
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))
+ .addReg(AVR::R0, RegState::Kill)
+ .setMIFlag(MachineInstr::FrameSetup);
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::EORRdRr))
+ .addReg(AVR::R0, RegState::Define)
+ .addReg(AVR::R0, RegState::Kill)
+ .addReg(AVR::R0, RegState::Kill)
+ .setMIFlag(MachineInstr::FrameSetup);
+ }
+
+ // Early exit if the frame pointer is not needed in this function.
+ if (!hasFP(MF)) {
+ return;
+ }
+
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+ unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();
+
+ // Skip the callee-saved push instructions.
+ while (
+ (MBBI != MBB.end()) && MBBI->getFlag(MachineInstr::FrameSetup) &&
+ (MBBI->getOpcode() == AVR::PUSHRr || MBBI->getOpcode() == AVR::PUSHWRr)) {
+ ++MBBI;
+ }
+
+ // Update Y with the new base value.
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::SPREAD), AVR::R29R28)
+ .addReg(AVR::SP)
+ .setMIFlag(MachineInstr::FrameSetup);
+
+ // Mark the FramePtr as live-in in every block except the entry.
+ for (MachineFunction::iterator I = std::next(MF.begin()), E = MF.end();
+ I != E; ++I) {
+ I->addLiveIn(AVR::R29R28);
+ }
+
+ if (!FrameSize) {
+ return;
+ }
+
+ // Reserve the necessary frame memory by doing FP -= <size>.
+ unsigned Opcode = (isUInt<6>(FrameSize)) ? AVR::SBIWRdK : AVR::SUBIWRdK;
+
+ MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)
+ .addReg(AVR::R29R28, RegState::Kill)
+ .addImm(FrameSize)
+ .setMIFlag(MachineInstr::FrameSetup);
+ // The SREG implicit def is dead.
+ MI->getOperand(3).setIsDead();
+
+ // Write back R29R28 to SP and temporarily disable interrupts.
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)
+ .addReg(AVR::R29R28)
+ .setMIFlag(MachineInstr::FrameSetup);
+}
+
+void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ CallingConv::ID CallConv = MF.getFunction()->getCallingConv();
+ bool isHandler = (CallConv == CallingConv::AVR_INTR ||
+ CallConv == CallingConv::AVR_SIGNAL);
+
+ // Early exit if the frame pointer is not needed in this function except for
+ // signal/interrupt handlers where special code generation is required.
+ if (!hasFP(MF) && !isHandler) {
+ return;
+ }
+
+ MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
+ assert(MBBI->getDesc().isReturn() &&
+ "Can only insert epilog into returning blocks");
+
+ DebugLoc DL = MBBI->getDebugLoc();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+ unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const AVRInstrInfo &TII = *STI.getInstrInfo();
+
+ // Emit special epilogue code to restore R1, R0 and SREG in interrupt/signal
+ // handlers at the very end of the function, just before reti.
+ if (isHandler) {
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), AVR::R0);
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::OUTARr))
+ .addImm(0x3f)
+ .addReg(AVR::R0, RegState::Kill);
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::POPWRd), AVR::R1R0);
+ }
+
+ // Early exit if there is no need to restore the frame pointer.
+ if (!FrameSize) {
+ return;
+ }
+
+ // Skip the callee-saved pop instructions.
+ while (MBBI != MBB.begin()) {
+ MachineBasicBlock::iterator PI = std::prev(MBBI);
+ int Opc = PI->getOpcode();
+
+ if (Opc != AVR::POPRd && Opc != AVR::POPWRd && !PI->isTerminator()) {
+ break;
+ }
+
+ --MBBI;
+ }
+
+ unsigned Opcode;
+
+ // Select the optimal opcode depending on how big it is.
+ if (isUInt<6>(FrameSize)) {
+ Opcode = AVR::ADIWRdK;
+ } else {
+ Opcode = AVR::SUBIWRdK;
+ FrameSize = -FrameSize;
+ }
+
+ // Restore the frame pointer by doing FP += <size>.
+ MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)
+ .addReg(AVR::R29R28, RegState::Kill)
+ .addImm(FrameSize);
+ // The SREG implicit def is dead.
+ MI->getOperand(3).setIsDead();
+
+ // Write back R29R28 to SP and temporarily disable interrupts.
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)
+ .addReg(AVR::R29R28, RegState::Kill);
+}
+
+// Return true if the specified function should have a dedicated frame
+// pointer register. This is true if the function meets any of the following
+// conditions:
+// - a register has been spilled
+// - has allocas
+// - input arguments are passed using the stack
+//
+// Notice that strictly this is not a frame pointer because it contains SP after
+// frame allocation instead of having the original SP in function entry.
+bool AVRFrameLowering::hasFP(const MachineFunction &MF) const {
+ const AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
+
+ return (FuncInfo->getHasSpills() || FuncInfo->getHasAllocas() ||
+ FuncInfo->getHasStackArgs());
+}
+
+bool AVRFrameLowering::spillCalleeSavedRegisters(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
+ const std::vector<CalleeSavedInfo> &CSI,
+ const TargetRegisterInfo *TRI) const {
+ if (CSI.empty()) {
+ return false;
+ }
+
+ unsigned CalleeFrameSize = 0;
+ DebugLoc DL = MBB.findDebugLoc(MI);
+ MachineFunction &MF = *MBB.getParent();
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const TargetInstrInfo &TII = *STI.getInstrInfo();
+ AVRMachineFunctionInfo *AVRFI = MF.getInfo<AVRMachineFunctionInfo>();
+
+ for (unsigned i = CSI.size(); i != 0; --i) {
+ unsigned Reg = CSI[i - 1].getReg();
+ bool IsNotLiveIn = !MBB.isLiveIn(Reg);
+
+ assert(TRI->getMinimalPhysRegClass(Reg)->getSize() == 1 &&
+ "Invalid register size");
+
+ // Add the callee-saved register as live-in only if it is not already a
+ // live-in register, this usually happens with arguments that are passed
+ // through callee-saved registers.
+ if (IsNotLiveIn) {
+ MBB.addLiveIn(Reg);
+ }
+
+ // Do not kill the register when it is an input argument.
+ BuildMI(MBB, MI, DL, TII.get(AVR::PUSHRr))
+ .addReg(Reg, getKillRegState(IsNotLiveIn))
+ .setMIFlag(MachineInstr::FrameSetup);
+ ++CalleeFrameSize;
+ }
+
+ AVRFI->setCalleeSavedFrameSize(CalleeFrameSize);
+
+ return true;
+}
+
+bool AVRFrameLowering::restoreCalleeSavedRegisters(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
+ const std::vector<CalleeSavedInfo> &CSI,
+ const TargetRegisterInfo *TRI) const {
+ if (CSI.empty()) {
+ return false;
+ }
+
+ DebugLoc DL = MBB.findDebugLoc(MI);
+ const MachineFunction &MF = *MBB.getParent();
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const TargetInstrInfo &TII = *STI.getInstrInfo();
+
+ for (const CalleeSavedInfo &CCSI : CSI) {
+ unsigned Reg = CCSI.getReg();
+
+ assert(TRI->getMinimalPhysRegClass(Reg)->getSize() == 1 &&
+ "Invalid register size");
+
+ BuildMI(MBB, MI, DL, TII.get(AVR::POPRd), Reg);
+ }
+
+ return true;
+}
+
+/// Replace pseudo store instructions that pass arguments through the stack with
+/// real instructions. If insertPushes is true then all instructions are
+/// replaced with push instructions, otherwise regular std instructions are
+/// inserted.
+static void fixStackStores(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI,
+ const TargetInstrInfo &TII, bool insertPushes) {
+ const AVRSubtarget &STI = MBB.getParent()->getSubtarget<AVRSubtarget>();
+ const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
+
+ // Iterate through the BB until we hit a call instruction or we reach the end.
+ for (auto I = MI, E = MBB.end(); I != E && !I->isCall();) {
+ MachineBasicBlock::iterator NextMI = std::next(I);
+ MachineInstr &MI = *I;
+ unsigned Opcode = I->getOpcode();
+
+ // Only care of pseudo store instructions where SP is the base pointer.
+ if (Opcode != AVR::STDSPQRr && Opcode != AVR::STDWSPQRr) {
+ I = NextMI;
+ continue;
+ }
+
+ assert(MI.getOperand(0).getReg() == AVR::SP &&
+ "Invalid register, should be SP!");
+ if (insertPushes) {
+ // Replace this instruction with a push.
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ bool SrcIsKill = MI.getOperand(2).isKill();
+
+ // We can't use PUSHWRr here because when expanded the order of the new
+ // instructions are reversed from what we need. Perform the expansion now.
+ if (Opcode == AVR::STDWSPQRr) {
+ BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr))
+ .addReg(TRI.getSubReg(SrcReg, AVR::sub_hi),
+ getKillRegState(SrcIsKill));
+ BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr))
+ .addReg(TRI.getSubReg(SrcReg, AVR::sub_lo),
+ getKillRegState(SrcIsKill));
+ } else {
+ BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr))
+ .addReg(SrcReg, getKillRegState(SrcIsKill));
+ }
+
+ MI.eraseFromParent();
+ I = NextMI;
+ continue;
+ }
+
+ // Replace this instruction with a regular store. Use Y as the base
+ // pointer since it is guaranteed to contain a copy of SP.
+ unsigned STOpc =
+ (Opcode == AVR::STDWSPQRr) ? AVR::STDWPtrQRr : AVR::STDPtrQRr;
+
+ MI.setDesc(TII.get(STOpc));
+ MI.getOperand(0).setReg(AVR::R29R28);
+
+ I = NextMI;
+ }
+}
+
+MachineBasicBlock::iterator AVRFrameLowering::eliminateCallFramePseudoInstr(
+ MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI) const {
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const TargetFrameLowering &TFI = *STI.getFrameLowering();
+ const AVRInstrInfo &TII = *STI.getInstrInfo();
+
+ // There is nothing to insert when the call frame memory is allocated during
+ // function entry. Delete the call frame pseudo and replace all pseudo stores
+ // with real store instructions.
+ if (TFI.hasReservedCallFrame(MF)) {
+ fixStackStores(MBB, MI, TII, false);
+ return MBB.erase(MI);
+ }
+
+ DebugLoc DL = MI->getDebugLoc();
+ unsigned int Opcode = MI->getOpcode();
+ int Amount = MI->getOperand(0).getImm();
+
+ // Adjcallstackup does not need to allocate stack space for the call, instead
+ // we insert push instructions that will allocate the necessary stack.
+ // For adjcallstackdown we convert it into an 'adiw reg, <amt>' handling
+ // the read and write of SP in I/O space.
+ if (Amount != 0) {
+ assert(TFI.getStackAlignment() == 1 && "Unsupported stack alignment");
+
+ if (Opcode == TII.getCallFrameSetupOpcode()) {
+ fixStackStores(MBB, MI, TII, true);
+ } else {
+ assert(Opcode == TII.getCallFrameDestroyOpcode());
+
+ // Select the best opcode to adjust SP based on the offset size.
+ unsigned addOpcode;
+ if (isUInt<6>(Amount)) {
+ addOpcode = AVR::ADIWRdK;
+ } else {
+ addOpcode = AVR::SUBIWRdK;
+ Amount = -Amount;
+ }
+
+ // Build the instruction sequence.
+ BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);
+
+ MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(addOpcode), AVR::R31R30)
+ .addReg(AVR::R31R30, RegState::Kill)
+ .addImm(Amount);
+ New->getOperand(3).setIsDead();
+
+ BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP)
+ .addReg(AVR::R31R30, RegState::Kill);
+ }
+ }
+
+ return MBB.erase(MI);
+}
+
+void AVRFrameLowering::determineCalleeSaves(MachineFunction &MF,
+ BitVector &SavedRegs,
+ RegScavenger *RS) const {
+ TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
+
+ // Spill register Y when it is used as the frame pointer.
+ if (hasFP(MF)) {
+ SavedRegs.set(AVR::R29R28);
+ SavedRegs.set(AVR::R29);
+ SavedRegs.set(AVR::R28);
+ }
+}
+/// The frame analyzer pass.
+///
+/// Scans the function for allocas and used arguments
+/// that are passed through the stack.
+struct AVRFrameAnalyzer : public MachineFunctionPass {
+ static char ID;
+ AVRFrameAnalyzer() : MachineFunctionPass(ID) {}
+
+ bool runOnMachineFunction(MachineFunction &MF) {
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
+
+ // If there are no fixed frame indexes during this stage it means there
+ // are allocas present in the function.
+ if (MFI.getNumObjects() != MFI.getNumFixedObjects()) {
+ // Check for the type of allocas present in the function. We only care
+ // about fixed size allocas so do not give false positives if only
+ // variable sized allocas are present.
+ for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
+ // Variable sized objects have size 0.
+ if (MFI.getObjectSize(i)) {
+ FuncInfo->setHasAllocas(true);
+ break;
+ }
+ }
+ }
+
+ // If there are fixed frame indexes present, scan the function to see if
+ // they are really being used.
+ if (MFI.getNumFixedObjects() == 0) {
+ return false;
+ }
+
+ // Ok fixed frame indexes present, now scan the function to see if they
+ // are really being used, otherwise we can ignore them.
+ for (const MachineBasicBlock &BB : MF) {
+ for (const MachineInstr &MI : BB) {
+ int Opcode = MI.getOpcode();
+
+ if ((Opcode != AVR::LDDRdPtrQ) && (Opcode != AVR::LDDWRdPtrQ) &&
+ (Opcode != AVR::STDPtrQRr) && (Opcode != AVR::STDWPtrQRr)) {
+ continue;
+ }
+
+ for (const MachineOperand &MO : MI.operands()) {
+ if (!MO.isFI()) {
+ continue;
+ }
+
+ if (MFI.isFixedObjectIndex(MO.getIndex())) {
+ FuncInfo->setHasStackArgs(true);
+ return false;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ StringRef getPassName() const { return "AVR Frame Analyzer"; }
+};
+
+char AVRFrameAnalyzer::ID = 0;
+
+/// Creates instance of the frame analyzer pass.
+FunctionPass *createAVRFrameAnalyzerPass() { return new AVRFrameAnalyzer(); }
+
+/// Create the Dynalloca Stack Pointer Save/Restore pass.
+/// Insert a copy of SP before allocating the dynamic stack memory and restore
+/// it in function exit to restore the original SP state. This avoids the need
+/// of reserving a register pair for a frame pointer.
+struct AVRDynAllocaSR : public MachineFunctionPass {
+ static char ID;
+ AVRDynAllocaSR() : MachineFunctionPass(ID) {}
+
+ bool runOnMachineFunction(MachineFunction &MF) {
+ // Early exit when there are no variable sized objects in the function.
+ if (!MF.getFrameInfo().hasVarSizedObjects()) {
+ return false;
+ }
+
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const TargetInstrInfo &TII = *STI.getInstrInfo();
+ MachineBasicBlock &EntryMBB = MF.front();
+ MachineBasicBlock::iterator MBBI = EntryMBB.begin();
+ DebugLoc DL = EntryMBB.findDebugLoc(MBBI);
+
+ unsigned SPCopy =
+ MF.getRegInfo().createVirtualRegister(&AVR::DREGSRegClass);
+
+ // Create a copy of SP in function entry before any dynallocas are
+ // inserted.
+ BuildMI(EntryMBB, MBBI, DL, TII.get(AVR::COPY), SPCopy).addReg(AVR::SP);
+
+ // Restore SP in all exit basic blocks.
+ for (MachineBasicBlock &MBB : MF) {
+ // If last instruction is a return instruction, add a restore copy.
+ if (!MBB.empty() && MBB.back().isReturn()) {
+ MBBI = MBB.getLastNonDebugInstr();
+ DL = MBBI->getDebugLoc();
+ BuildMI(MBB, MBBI, DL, TII.get(AVR::COPY), AVR::SP)
+ .addReg(SPCopy, RegState::Kill);
+ }
+ }
+
+ return true;
+ }
+
+ StringRef getPassName() const {
+ return "AVR dynalloca stack pointer save/restore";
+ }
+};
+
+char AVRDynAllocaSR::ID = 0;
+
+/// createAVRDynAllocaSRPass - returns an instance of the dynalloca stack
+/// pointer save/restore pass.
+FunctionPass *createAVRDynAllocaSRPass() { return new AVRDynAllocaSR(); }
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp b/contrib/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
new file mode 100644
index 0000000..462a7d5
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
@@ -0,0 +1,565 @@
+//===-- AVRISelDAGToDAG.cpp - A dag to dag inst selector for AVR ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines an instruction selector for the AVR target.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRTargetMachine.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/SelectionDAGISel.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "avr-isel"
+
+namespace llvm {
+
+/// Lowers LLVM IR (in DAG form) to AVR MC instructions (in DAG form).
+class AVRDAGToDAGISel : public SelectionDAGISel {
+public:
+ AVRDAGToDAGISel(AVRTargetMachine &TM, CodeGenOpt::Level OptLevel)
+ : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {}
+
+ StringRef getPassName() const override {
+ return "AVR DAG->DAG Instruction Selection";
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ bool SelectAddr(SDNode *Op, SDValue N, SDValue &Base, SDValue &Disp);
+
+ bool selectIndexedLoad(SDNode *N);
+ unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT);
+
+ bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
+ std::vector<SDValue> &OutOps) override;
+
+// Include the pieces autogenerated from the target description.
+#include "AVRGenDAGISel.inc"
+
+private:
+ void Select(SDNode *N) override;
+ bool trySelect(SDNode *N);
+
+ template <unsigned NodeType> bool select(SDNode *N);
+ bool selectMultiplication(SDNode *N);
+
+ const AVRSubtarget *Subtarget;
+};
+
+bool AVRDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
+ Subtarget = &MF.getSubtarget<AVRSubtarget>();
+ return SelectionDAGISel::runOnMachineFunction(MF);
+}
+
+bool AVRDAGToDAGISel::SelectAddr(SDNode *Op, SDValue N, SDValue &Base,
+ SDValue &Disp) {
+ SDLoc dl(Op);
+ auto DL = CurDAG->getDataLayout();
+ MVT PtrVT = getTargetLowering()->getPointerTy(DL);
+
+ // if the address is a frame index get the TargetFrameIndex.
+ if (const FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N)) {
+ Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);
+ Disp = CurDAG->getTargetConstant(0, dl, MVT::i8);
+
+ return true;
+ }
+
+ // Match simple Reg + uimm6 operands.
+ if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
+ !CurDAG->isBaseWithConstantOffset(N)) {
+ return false;
+ }
+
+ if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
+ int RHSC = (int)RHS->getZExtValue();
+
+ // Convert negative offsets into positives ones.
+ if (N.getOpcode() == ISD::SUB) {
+ RHSC = -RHSC;
+ }
+
+ // <#Frame index + const>
+ // Allow folding offsets bigger than 63 so the frame pointer can be used
+ // directly instead of copying it around by adjusting and restoring it for
+ // each access.
+ if (N.getOperand(0).getOpcode() == ISD::FrameIndex) {
+ int FI = cast<FrameIndexSDNode>(N.getOperand(0))->getIndex();
+
+ Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
+ Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);
+
+ return true;
+ }
+
+ // The value type of the memory instruction determines what is the maximum
+ // offset allowed.
+ MVT VT = cast<MemSDNode>(Op)->getMemoryVT().getSimpleVT();
+
+ // We only accept offsets that fit in 6 bits (unsigned).
+ if (isUInt<6>(RHSC) && (VT == MVT::i8 || VT == MVT::i16)) {
+ Base = N.getOperand(0);
+ Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) {
+ const LoadSDNode *LD = cast<LoadSDNode>(N);
+ ISD::MemIndexedMode AM = LD->getAddressingMode();
+ MVT VT = LD->getMemoryVT().getSimpleVT();
+ auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
+
+ // We only care if this load uses a POSTINC or PREDEC mode.
+ if ((LD->getExtensionType() != ISD::NON_EXTLOAD) ||
+ (AM != ISD::POST_INC && AM != ISD::PRE_DEC)) {
+
+ return false;
+ }
+
+ unsigned Opcode = 0;
+ bool isPre = (AM == ISD::PRE_DEC);
+ int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue();
+
+ switch (VT.SimpleTy) {
+ case MVT::i8: {
+ if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
+ return false;
+ }
+
+ Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
+ break;
+ }
+ case MVT::i16: {
+ if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
+ return false;
+ }
+
+ Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
+ break;
+ }
+ default:
+ return false;
+ }
+
+ SDNode *ResNode = CurDAG->getMachineNode(Opcode, SDLoc(N), VT,
+ PtrVT, MVT::Other,
+ LD->getBasePtr(), LD->getChain());
+ ReplaceUses(N, ResNode);
+ CurDAG->RemoveDeadNode(N);
+
+ return true;
+}
+
+unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD,
+ MVT VT) {
+ ISD::MemIndexedMode AM = LD->getAddressingMode();
+
+ // Progmem indexed loads only work in POSTINC mode.
+ if (LD->getExtensionType() != ISD::NON_EXTLOAD || AM != ISD::POST_INC) {
+ return 0;
+ }
+
+ unsigned Opcode = 0;
+ int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue();
+
+ switch (VT.SimpleTy) {
+ case MVT::i8: {
+ if (Offs != 1) {
+ return 0;
+ }
+ Opcode = AVR::LPMRdZPi;
+ break;
+ }
+ case MVT::i16: {
+ if (Offs != 2) {
+ return 0;
+ }
+ Opcode = AVR::LPMWRdZPi;
+ break;
+ }
+ default:
+ return 0;
+ }
+
+ return Opcode;
+}
+
+bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
+ unsigned ConstraintCode,
+ std::vector<SDValue> &OutOps) {
+ assert((ConstraintCode == InlineAsm::Constraint_m ||
+ ConstraintCode == InlineAsm::Constraint_Q) &&
+ "Unexpected asm memory constraint");
+
+ MachineRegisterInfo &RI = MF->getRegInfo();
+ const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
+ const TargetLowering &TL = *STI.getTargetLowering();
+ SDLoc dl(Op);
+ auto DL = CurDAG->getDataLayout();
+
+ const RegisterSDNode *RegNode = dyn_cast<RegisterSDNode>(Op);
+
+ // If address operand is of PTRDISPREGS class, all is OK, then.
+ if (RegNode &&
+ RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) {
+ OutOps.push_back(Op);
+ return false;
+ }
+
+ if (Op->getOpcode() == ISD::FrameIndex) {
+ SDValue Base, Disp;
+
+ if (SelectAddr(Op.getNode(), Op, Base, Disp)) {
+ OutOps.push_back(Base);
+ OutOps.push_back(Disp);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ // If Op is add 'register, immediate' and
+ // register is either virtual register or register of PTRDISPREGSRegClass
+ if (Op->getOpcode() == ISD::ADD || Op->getOpcode() == ISD::SUB) {
+ SDValue CopyFromRegOp = Op->getOperand(0);
+ SDValue ImmOp = Op->getOperand(1);
+ ConstantSDNode *ImmNode = dyn_cast<ConstantSDNode>(ImmOp);
+
+ unsigned Reg;
+ bool CanHandleRegImmOpt = true;
+
+ CanHandleRegImmOpt &= ImmNode != 0;
+ CanHandleRegImmOpt &= ImmNode->getAPIntValue().getZExtValue() < 64;
+
+ if (CopyFromRegOp->getOpcode() == ISD::CopyFromReg) {
+ RegisterSDNode *RegNode =
+ cast<RegisterSDNode>(CopyFromRegOp->getOperand(1));
+ Reg = RegNode->getReg();
+ CanHandleRegImmOpt &= (TargetRegisterInfo::isVirtualRegister(Reg) ||
+ AVR::PTRDISPREGSRegClass.contains(Reg));
+ } else {
+ CanHandleRegImmOpt = false;
+ }
+
+ // If we detect proper case - correct virtual register class
+ // if needed and go to another inlineasm operand.
+ if (CanHandleRegImmOpt) {
+ SDValue Base, Disp;
+
+ if (RI.getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) {
+ SDLoc dl(CopyFromRegOp);
+
+ unsigned VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass);
+
+ SDValue CopyToReg =
+ CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
+
+ SDValue NewCopyFromRegOp =
+ CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
+
+ Base = NewCopyFromRegOp;
+ } else {
+ Base = CopyFromRegOp;
+ }
+
+ if (ImmNode->getValueType(0) != MVT::i8) {
+ Disp = CurDAG->getTargetConstant(ImmNode->getAPIntValue().getZExtValue(), dl, MVT::i8);
+ } else {
+ Disp = ImmOp;
+ }
+
+ OutOps.push_back(Base);
+ OutOps.push_back(Disp);
+
+ return false;
+ }
+ }
+
+ // More generic case.
+ // Create chain that puts Op into pointer register
+ // and return that register.
+ unsigned VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass);
+
+ SDValue CopyToReg = CurDAG->getCopyToReg(Op, dl, VReg, Op);
+ SDValue CopyFromReg =
+ CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
+
+ OutOps.push_back(CopyFromReg);
+
+ return false;
+}
+
+template <> bool AVRDAGToDAGISel::select<ISD::FrameIndex>(SDNode *N) {
+ auto DL = CurDAG->getDataLayout();
+
+ // Convert the frameindex into a temp instruction that will hold the
+ // effective address of the final stack slot.
+ int FI = cast<FrameIndexSDNode>(N)->getIndex();
+ SDValue TFI =
+ CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(DL));
+
+ CurDAG->SelectNodeTo(N, AVR::FRMIDX,
+ getTargetLowering()->getPointerTy(DL), TFI,
+ CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16));
+ return true;
+}
+
+template <> bool AVRDAGToDAGISel::select<ISD::STORE>(SDNode *N) {
+ // Use the STD{W}SPQRr pseudo instruction when passing arguments through
+ // the stack on function calls for further expansion during the PEI phase.
+ const StoreSDNode *ST = cast<StoreSDNode>(N);
+ SDValue BasePtr = ST->getBasePtr();
+
+ // Early exit when the base pointer is a frame index node or a constant.
+ if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) ||
+ BasePtr.isUndef()) {
+ return false;
+ }
+
+ const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0));
+ // Only stores where SP is the base pointer are valid.
+ if (!RN || (RN->getReg() != AVR::SP)) {
+ return false;
+ }
+
+ int CST = (int)cast<ConstantSDNode>(BasePtr.getOperand(1))->getZExtValue();
+ SDValue Chain = ST->getChain();
+ EVT VT = ST->getValue().getValueType();
+ SDLoc DL(N);
+ SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16);
+ SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain};
+ unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
+
+ SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops);
+
+ // Transfer memory operands.
+ MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
+ MemOp[0] = ST->getMemOperand();
+ cast<MachineSDNode>(ResNode)->setMemRefs(MemOp, MemOp + 1);
+
+ ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
+ CurDAG->RemoveDeadNode(N);
+
+ return true;
+}
+
+template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) {
+ const LoadSDNode *LD = cast<LoadSDNode>(N);
+ if (!AVR::isProgramMemoryAccess(LD)) {
+ // Check if the opcode can be converted into an indexed load.
+ return selectIndexedLoad(N);
+ }
+
+ assert(Subtarget->hasLPM() && "cannot load from program memory on this mcu");
+
+ // This is a flash memory load, move the pointer into R31R30 and emit
+ // the lpm instruction.
+ MVT VT = LD->getMemoryVT().getSimpleVT();
+ SDValue Chain = LD->getChain();
+ SDValue Ptr = LD->getBasePtr();
+ SDNode *ResNode;
+ SDLoc DL(N);
+
+ Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Ptr, SDValue());
+ Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16,
+ Chain.getValue(1));
+
+ SDValue RegZ = CurDAG->getRegister(AVR::R31R30, MVT::i16);
+
+ // Check if the opcode can be converted into an indexed load.
+ if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT)) {
+ // It is legal to fold the load into an indexed load.
+ ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr,
+ RegZ);
+ ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
+ } else {
+ // Selecting an indexed load is not legal, fallback to a normal load.
+ switch (VT.SimpleTy) {
+ case MVT::i8:
+ ResNode = CurDAG->getMachineNode(AVR::LPMRdZ, DL, MVT::i8, MVT::Other,
+ Ptr, RegZ);
+ break;
+ case MVT::i16:
+ ResNode = CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16,
+ MVT::Other, Ptr, RegZ);
+ ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
+ break;
+ default:
+ llvm_unreachable("Unsupported VT!");
+ }
+ }
+
+ // Transfer memory operands.
+ MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
+ MemOp[0] = LD->getMemOperand();
+ cast<MachineSDNode>(ResNode)->setMemRefs(MemOp, MemOp + 1);
+
+ ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
+ ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
+ CurDAG->RemoveDeadNode(N);
+
+ return true;
+}
+
+template <> bool AVRDAGToDAGISel::select<AVRISD::CALL>(SDNode *N) {
+ SDValue InFlag;
+ SDValue Chain = N->getOperand(0);
+ SDValue Callee = N->getOperand(1);
+ unsigned LastOpNum = N->getNumOperands() - 1;
+
+ // Direct calls are autogenerated.
+ unsigned Op = Callee.getOpcode();
+ if (Op == ISD::TargetGlobalAddress || Op == ISD::TargetExternalSymbol) {
+ return false;
+ }
+
+ // Skip the incoming flag if present
+ if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
+ --LastOpNum;
+ }
+
+ SDLoc DL(N);
+ Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InFlag);
+ SmallVector<SDValue, 8> Ops;
+ Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
+
+ // Map all operands into the new node.
+ for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
+ Ops.push_back(N->getOperand(i));
+ }
+
+ Ops.push_back(Chain);
+ Ops.push_back(Chain.getValue(1));
+
+ SDNode *ResNode =
+ CurDAG->getMachineNode(AVR::ICALL, DL, MVT::Other, MVT::Glue, Ops);
+
+ ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
+ ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
+ CurDAG->RemoveDeadNode(N);
+
+ return true;
+}
+
+template <> bool AVRDAGToDAGISel::select<ISD::BRIND>(SDNode *N) {
+ SDValue Chain = N->getOperand(0);
+ SDValue JmpAddr = N->getOperand(1);
+
+ SDLoc DL(N);
+ // Move the destination address of the indirect branch into R31R30.
+ Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr);
+ SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain);
+
+ ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
+ CurDAG->RemoveDeadNode(N);
+
+ return true;
+}
+
+bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) {
+ SDLoc DL(N);
+ MVT Type = N->getSimpleValueType(0);
+
+ assert(Type == MVT::i8 && "unexpected value type");
+
+ bool isSigned = N->getOpcode() == ISD::SMUL_LOHI;
+ unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
+
+ SDValue Lhs = N->getOperand(0);
+ SDValue Rhs = N->getOperand(1);
+ SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, Rhs);
+ SDValue InChain = CurDAG->getEntryNode();
+ SDValue InGlue = SDValue(Mul, 0);
+
+ // Copy the low half of the result, if it is needed.
+ if (N->hasAnyUseOfValue(0)) {
+ SDValue CopyFromLo =
+ CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue);
+
+ ReplaceUses(SDValue(N, 0), CopyFromLo);
+
+ InChain = CopyFromLo.getValue(1);
+ InGlue = CopyFromLo.getValue(2);
+ }
+
+ // Copy the high half of the result, if it is needed.
+ if (N->hasAnyUseOfValue(1)) {
+ SDValue CopyFromHi =
+ CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue);
+
+ ReplaceUses(SDValue(N, 1), CopyFromHi);
+
+ InChain = CopyFromHi.getValue(1);
+ InGlue = CopyFromHi.getValue(2);
+ }
+
+ CurDAG->RemoveDeadNode(N);
+
+ // We need to clear R1. This is currently done (dirtily)
+ // using a custom inserter.
+
+ return true;
+}
+
+void AVRDAGToDAGISel::Select(SDNode *N) {
+ // Dump information about the Node being selected
+ DEBUG(errs() << "Selecting: "; N->dump(CurDAG); errs() << "\n");
+
+ // If we have a custom node, we already have selected!
+ if (N->isMachineOpcode()) {
+ DEBUG(errs() << "== "; N->dump(CurDAG); errs() << "\n");
+ N->setNodeId(-1);
+ return;
+ }
+
+ // See if subclasses can handle this node.
+ if (trySelect(N))
+ return;
+
+ // Select the default instruction
+ SelectCode(N);
+}
+
+bool AVRDAGToDAGISel::trySelect(SDNode *N) {
+ unsigned Opcode = N->getOpcode();
+ SDLoc DL(N);
+
+ switch (Opcode) {
+ // Nodes we fully handle.
+ case ISD::FrameIndex: return select<ISD::FrameIndex>(N);
+ case ISD::BRIND: return select<ISD::BRIND>(N);
+ case ISD::UMUL_LOHI:
+ case ISD::SMUL_LOHI: return selectMultiplication(N);
+
+ // Nodes we handle partially. Other cases are autogenerated
+ case ISD::STORE: return select<ISD::STORE>(N);
+ case ISD::LOAD: return select<ISD::LOAD>(N);
+ case AVRISD::CALL: return select<AVRISD::CALL>(N);
+ default: return false;
+ }
+}
+
+FunctionPass *createAVRISelDag(AVRTargetMachine &TM,
+ CodeGenOpt::Level OptLevel) {
+ return new AVRDAGToDAGISel(TM, OptLevel);
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRISelLowering.cpp b/contrib/llvm/lib/Target/AVR/AVRISelLowering.cpp
new file mode 100644
index 0000000..07fc3f6
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRISelLowering.cpp
@@ -0,0 +1,1978 @@
+//===-- AVRISelLowering.cpp - AVR DAG Lowering Implementation -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the interfaces that AVR uses to lower LLVM code into a
+// selection DAG.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRISelLowering.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#include "AVR.h"
+#include "AVRMachineFunctionInfo.h"
+#include "AVRTargetMachine.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+namespace llvm {
+
+AVRTargetLowering::AVRTargetLowering(AVRTargetMachine &tm)
+ : TargetLowering(tm) {
+ // Set up the register classes.
+ addRegisterClass(MVT::i8, &AVR::GPR8RegClass);
+ addRegisterClass(MVT::i16, &AVR::DREGSRegClass);
+
+ // Compute derived properties from the register classes.
+ computeRegisterProperties(tm.getSubtargetImpl()->getRegisterInfo());
+
+ setBooleanContents(ZeroOrOneBooleanContent);
+ setBooleanVectorContents(ZeroOrOneBooleanContent);
+ setSchedulingPreference(Sched::RegPressure);
+ setStackPointerRegisterToSaveRestore(AVR::SP);
+
+ setOperationAction(ISD::GlobalAddress, MVT::i16, Custom);
+ setOperationAction(ISD::BlockAddress, MVT::i16, Custom);
+
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i8, Expand);
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i16, Expand);
+
+ for (MVT VT : MVT::integer_valuetypes()) {
+ for (auto N : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) {
+ setLoadExtAction(N, VT, MVT::i1, Promote);
+ setLoadExtAction(N, VT, MVT::i8, Expand);
+ }
+ }
+
+ setTruncStoreAction(MVT::i16, MVT::i8, Expand);
+
+ // sub (x, imm) gets canonicalized to add (x, -imm), so for illegal types
+ // revert into a sub since we don't have an add with immediate instruction.
+ setOperationAction(ISD::ADD, MVT::i32, Custom);
+ setOperationAction(ISD::ADD, MVT::i64, Custom);
+
+ // our shift instructions are only able to shift 1 bit at a time, so handle
+ // this in a custom way.
+ setOperationAction(ISD::SRA, MVT::i8, Custom);
+ setOperationAction(ISD::SHL, MVT::i8, Custom);
+ setOperationAction(ISD::SRL, MVT::i8, Custom);
+ setOperationAction(ISD::SRA, MVT::i16, Custom);
+ setOperationAction(ISD::SHL, MVT::i16, Custom);
+ setOperationAction(ISD::SRL, MVT::i16, Custom);
+ setOperationAction(ISD::SHL_PARTS, MVT::i16, Expand);
+ setOperationAction(ISD::SRA_PARTS, MVT::i16, Expand);
+ setOperationAction(ISD::SRL_PARTS, MVT::i16, Expand);
+
+ setOperationAction(ISD::BR_CC, MVT::i8, Custom);
+ setOperationAction(ISD::BR_CC, MVT::i16, Custom);
+ setOperationAction(ISD::BR_CC, MVT::i32, Custom);
+ setOperationAction(ISD::BR_CC, MVT::i64, Custom);
+ setOperationAction(ISD::BRCOND, MVT::Other, Expand);
+
+ setOperationAction(ISD::SELECT_CC, MVT::i8, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::i16, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::i32, Expand);
+ setOperationAction(ISD::SELECT_CC, MVT::i64, Expand);
+ setOperationAction(ISD::SETCC, MVT::i8, Custom);
+ setOperationAction(ISD::SETCC, MVT::i16, Custom);
+ setOperationAction(ISD::SETCC, MVT::i32, Custom);
+ setOperationAction(ISD::SETCC, MVT::i64, Custom);
+ setOperationAction(ISD::SELECT, MVT::i8, Expand);
+ setOperationAction(ISD::SELECT, MVT::i16, Expand);
+
+ setOperationAction(ISD::BSWAP, MVT::i16, Expand);
+
+ // Add support for postincrement and predecrement load/stores.
+ setIndexedLoadAction(ISD::POST_INC, MVT::i8, Legal);
+ setIndexedLoadAction(ISD::POST_INC, MVT::i16, Legal);
+ setIndexedLoadAction(ISD::PRE_DEC, MVT::i8, Legal);
+ setIndexedLoadAction(ISD::PRE_DEC, MVT::i16, Legal);
+ setIndexedStoreAction(ISD::POST_INC, MVT::i8, Legal);
+ setIndexedStoreAction(ISD::POST_INC, MVT::i16, Legal);
+ setIndexedStoreAction(ISD::PRE_DEC, MVT::i8, Legal);
+ setIndexedStoreAction(ISD::PRE_DEC, MVT::i16, Legal);
+
+ setOperationAction(ISD::BR_JT, MVT::Other, Expand);
+
+ setOperationAction(ISD::VASTART, MVT::Other, Custom);
+ setOperationAction(ISD::VAEND, MVT::Other, Expand);
+ setOperationAction(ISD::VAARG, MVT::Other, Expand);
+ setOperationAction(ISD::VACOPY, MVT::Other, Expand);
+
+ // Atomic operations which must be lowered to rtlib calls
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setOperationAction(ISD::ATOMIC_SWAP, VT, Expand);
+ setOperationAction(ISD::ATOMIC_CMP_SWAP, VT, Expand);
+ setOperationAction(ISD::ATOMIC_LOAD_NAND, VT, Expand);
+ setOperationAction(ISD::ATOMIC_LOAD_MAX, VT, Expand);
+ setOperationAction(ISD::ATOMIC_LOAD_MIN, VT, Expand);
+ setOperationAction(ISD::ATOMIC_LOAD_UMAX, VT, Expand);
+ setOperationAction(ISD::ATOMIC_LOAD_UMIN, VT, Expand);
+ }
+
+ // Division/remainder
+ setOperationAction(ISD::UDIV, MVT::i8, Expand);
+ setOperationAction(ISD::UDIV, MVT::i16, Expand);
+ setOperationAction(ISD::UREM, MVT::i8, Expand);
+ setOperationAction(ISD::UREM, MVT::i16, Expand);
+ setOperationAction(ISD::SDIV, MVT::i8, Expand);
+ setOperationAction(ISD::SDIV, MVT::i16, Expand);
+ setOperationAction(ISD::SREM, MVT::i8, Expand);
+ setOperationAction(ISD::SREM, MVT::i16, Expand);
+
+ // Make division and modulus custom
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setOperationAction(ISD::UDIVREM, VT, Custom);
+ setOperationAction(ISD::SDIVREM, VT, Custom);
+ }
+
+ // Do not use MUL. The AVR instructions are closer to SMUL_LOHI &co.
+ setOperationAction(ISD::MUL, MVT::i8, Expand);
+ setOperationAction(ISD::MUL, MVT::i16, Expand);
+
+ // Expand 16 bit multiplications.
+ setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand);
+ setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand);
+
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setOperationAction(ISD::MULHS, VT, Expand);
+ setOperationAction(ISD::MULHU, VT, Expand);
+ }
+
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setOperationAction(ISD::CTPOP, VT, Expand);
+ setOperationAction(ISD::CTLZ, VT, Expand);
+ setOperationAction(ISD::CTTZ, VT, Expand);
+ }
+
+ for (MVT VT : MVT::integer_valuetypes()) {
+ setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand);
+ // TODO: The generated code is pretty poor. Investigate using the
+ // same "shift and subtract with carry" trick that we do for
+ // extending 8-bit to 16-bit. This may require infrastructure
+ // improvements in how we treat 16-bit "registers" to be feasible.
+ }
+
+ // Division rtlib functions (not supported)
+ setLibcallName(RTLIB::SDIV_I8, nullptr);
+ setLibcallName(RTLIB::SDIV_I16, nullptr);
+ setLibcallName(RTLIB::SDIV_I32, nullptr);
+ setLibcallName(RTLIB::SDIV_I64, nullptr);
+ setLibcallName(RTLIB::SDIV_I128, nullptr);
+ setLibcallName(RTLIB::UDIV_I8, nullptr);
+ setLibcallName(RTLIB::UDIV_I16, nullptr);
+ setLibcallName(RTLIB::UDIV_I32, nullptr);
+ setLibcallName(RTLIB::UDIV_I64, nullptr);
+ setLibcallName(RTLIB::UDIV_I128, nullptr);
+
+ // Modulus rtlib functions (not supported)
+ setLibcallName(RTLIB::SREM_I8, nullptr);
+ setLibcallName(RTLIB::SREM_I16, nullptr);
+ setLibcallName(RTLIB::SREM_I32, nullptr);
+ setLibcallName(RTLIB::SREM_I64, nullptr);
+ setLibcallName(RTLIB::SREM_I128, nullptr);
+ setLibcallName(RTLIB::UREM_I8, nullptr);
+ setLibcallName(RTLIB::UREM_I16, nullptr);
+ setLibcallName(RTLIB::UREM_I32, nullptr);
+ setLibcallName(RTLIB::UREM_I64, nullptr);
+ setLibcallName(RTLIB::UREM_I128, nullptr);
+
+ // Division and modulus rtlib functions
+ setLibcallName(RTLIB::SDIVREM_I8, "__divmodqi4");
+ setLibcallName(RTLIB::SDIVREM_I16, "__divmodhi4");
+ setLibcallName(RTLIB::SDIVREM_I32, "__divmodsi4");
+ setLibcallName(RTLIB::SDIVREM_I64, "__divmoddi4");
+ setLibcallName(RTLIB::SDIVREM_I128, "__divmodti4");
+ setLibcallName(RTLIB::UDIVREM_I8, "__udivmodqi4");
+ setLibcallName(RTLIB::UDIVREM_I16, "__udivmodhi4");
+ setLibcallName(RTLIB::UDIVREM_I32, "__udivmodsi4");
+ setLibcallName(RTLIB::UDIVREM_I64, "__udivmoddi4");
+ setLibcallName(RTLIB::UDIVREM_I128, "__udivmodti4");
+
+ // Several of the runtime library functions use a special calling conv
+ setLibcallCallingConv(RTLIB::SDIVREM_I8, CallingConv::AVR_BUILTIN);
+ setLibcallCallingConv(RTLIB::SDIVREM_I16, CallingConv::AVR_BUILTIN);
+ setLibcallCallingConv(RTLIB::UDIVREM_I8, CallingConv::AVR_BUILTIN);
+ setLibcallCallingConv(RTLIB::UDIVREM_I16, CallingConv::AVR_BUILTIN);
+
+ // Trigonometric rtlib functions
+ setLibcallName(RTLIB::SIN_F32, "sin");
+ setLibcallName(RTLIB::COS_F32, "cos");
+
+ setMinFunctionAlignment(1);
+ setMinimumJumpTableEntries(INT_MAX);
+}
+
+const char *AVRTargetLowering::getTargetNodeName(unsigned Opcode) const {
+#define NODE(name) \
+ case AVRISD::name: \
+ return #name
+
+ switch (Opcode) {
+ default:
+ return nullptr;
+ NODE(RET_FLAG);
+ NODE(RETI_FLAG);
+ NODE(CALL);
+ NODE(WRAPPER);
+ NODE(LSL);
+ NODE(LSR);
+ NODE(ROL);
+ NODE(ROR);
+ NODE(ASR);
+ NODE(LSLLOOP);
+ NODE(LSRLOOP);
+ NODE(ASRLOOP);
+ NODE(BRCOND);
+ NODE(CMP);
+ NODE(CMPC);
+ NODE(TST);
+ NODE(SELECT_CC);
+#undef NODE
+ }
+}
+
+EVT AVRTargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &,
+ EVT VT) const {
+ assert(!VT.isVector() && "No AVR SetCC type for vectors!");
+ return MVT::i8;
+}
+
+SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
+ //:TODO: this function has to be completely rewritten to produce optimal
+ // code, for now it's producing very long but correct code.
+ unsigned Opc8;
+ const SDNode *N = Op.getNode();
+ EVT VT = Op.getValueType();
+ SDLoc dl(N);
+
+ // Expand non-constant shifts to loops.
+ if (!isa<ConstantSDNode>(N->getOperand(1))) {
+ switch (Op.getOpcode()) {
+ default:
+ llvm_unreachable("Invalid shift opcode!");
+ case ISD::SHL:
+ return DAG.getNode(AVRISD::LSLLOOP, dl, VT, N->getOperand(0),
+ N->getOperand(1));
+ case ISD::SRL:
+ return DAG.getNode(AVRISD::LSRLOOP, dl, VT, N->getOperand(0),
+ N->getOperand(1));
+ case ISD::SRA:
+ return DAG.getNode(AVRISD::ASRLOOP, dl, VT, N->getOperand(0),
+ N->getOperand(1));
+ }
+ }
+
+ uint64_t ShiftAmount = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
+ SDValue Victim = N->getOperand(0);
+
+ switch (Op.getOpcode()) {
+ case ISD::SRA:
+ Opc8 = AVRISD::ASR;
+ break;
+ case ISD::ROTL:
+ Opc8 = AVRISD::ROL;
+ break;
+ case ISD::ROTR:
+ Opc8 = AVRISD::ROR;
+ break;
+ case ISD::SRL:
+ Opc8 = AVRISD::LSR;
+ break;
+ case ISD::SHL:
+ Opc8 = AVRISD::LSL;
+ break;
+ default:
+ llvm_unreachable("Invalid shift opcode");
+ }
+
+ while (ShiftAmount--) {
+ Victim = DAG.getNode(Opc8, dl, VT, Victim);
+ }
+
+ return Victim;
+}
+
+SDValue AVRTargetLowering::LowerDivRem(SDValue Op, SelectionDAG &DAG) const {
+ unsigned Opcode = Op->getOpcode();
+ assert((Opcode == ISD::SDIVREM || Opcode == ISD::UDIVREM) &&
+ "Invalid opcode for Div/Rem lowering");
+ bool isSigned = (Opcode == ISD::SDIVREM);
+ EVT VT = Op->getValueType(0);
+ Type *Ty = VT.getTypeForEVT(*DAG.getContext());
+
+ RTLIB::Libcall LC;
+ switch (VT.getSimpleVT().SimpleTy) {
+ default:
+ llvm_unreachable("Unexpected request for libcall!");
+ case MVT::i8:
+ LC = isSigned ? RTLIB::SDIVREM_I8 : RTLIB::UDIVREM_I8;
+ break;
+ case MVT::i16:
+ LC = isSigned ? RTLIB::SDIVREM_I16 : RTLIB::UDIVREM_I16;
+ break;
+ case MVT::i32:
+ LC = isSigned ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;
+ break;
+ case MVT::i64:
+ LC = isSigned ? RTLIB::SDIVREM_I64 : RTLIB::UDIVREM_I64;
+ break;
+ }
+
+ SDValue InChain = DAG.getEntryNode();
+
+ TargetLowering::ArgListTy Args;
+ TargetLowering::ArgListEntry Entry;
+ for (SDValue const &Value : Op->op_values()) {
+ Entry.Node = Value;
+ Entry.Ty = Value.getValueType().getTypeForEVT(*DAG.getContext());
+ Entry.isSExt = isSigned;
+ Entry.isZExt = !isSigned;
+ Args.push_back(Entry);
+ }
+
+ SDValue Callee = DAG.getExternalSymbol(getLibcallName(LC),
+ getPointerTy(DAG.getDataLayout()));
+
+ Type *RetTy = (Type *)StructType::get(Ty, Ty, nullptr);
+
+ SDLoc dl(Op);
+ TargetLowering::CallLoweringInfo CLI(DAG);
+ CLI.setDebugLoc(dl)
+ .setChain(InChain)
+ .setCallee(getLibcallCallingConv(LC), RetTy, Callee, std::move(Args))
+ .setInRegister()
+ .setSExtResult(isSigned)
+ .setZExtResult(!isSigned);
+
+ std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI);
+ return CallInfo.first;
+}
+
+SDValue AVRTargetLowering::LowerGlobalAddress(SDValue Op,
+ SelectionDAG &DAG) const {
+ auto DL = DAG.getDataLayout();
+
+ const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
+ int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset();
+
+ // Create the TargetGlobalAddress node, folding in the constant offset.
+ SDValue Result =
+ DAG.getTargetGlobalAddress(GV, SDLoc(Op), getPointerTy(DL), Offset);
+ return DAG.getNode(AVRISD::WRAPPER, SDLoc(Op), getPointerTy(DL), Result);
+}
+
+SDValue AVRTargetLowering::LowerBlockAddress(SDValue Op,
+ SelectionDAG &DAG) const {
+ auto DL = DAG.getDataLayout();
+ const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
+
+ SDValue Result = DAG.getTargetBlockAddress(BA, getPointerTy(DL));
+
+ return DAG.getNode(AVRISD::WRAPPER, SDLoc(Op), getPointerTy(DL), Result);
+}
+
+/// IntCCToAVRCC - Convert a DAG integer condition code to an AVR CC.
+static AVRCC::CondCodes intCCToAVRCC(ISD::CondCode CC) {
+ switch (CC) {
+ default:
+ llvm_unreachable("Unknown condition code!");
+ case ISD::SETEQ:
+ return AVRCC::COND_EQ;
+ case ISD::SETNE:
+ return AVRCC::COND_NE;
+ case ISD::SETGE:
+ return AVRCC::COND_GE;
+ case ISD::SETLT:
+ return AVRCC::COND_LT;
+ case ISD::SETUGE:
+ return AVRCC::COND_SH;
+ case ISD::SETULT:
+ return AVRCC::COND_LO;
+ }
+}
+
+/// Returns appropriate AVR CMP/CMPC nodes and corresponding condition code for
+/// the given operands.
+SDValue AVRTargetLowering::getAVRCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
+ SDValue &AVRcc, SelectionDAG &DAG,
+ SDLoc DL) const {
+ SDValue Cmp;
+ EVT VT = LHS.getValueType();
+ bool UseTest = false;
+
+ switch (CC) {
+ default:
+ break;
+ case ISD::SETLE: {
+ // Swap operands and reverse the branching condition.
+ std::swap(LHS, RHS);
+ CC = ISD::SETGE;
+ break;
+ }
+ case ISD::SETGT: {
+ if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
+ switch (C->getSExtValue()) {
+ case -1: {
+ // When doing lhs > -1 use a tst instruction on the top part of lhs
+ // and use brpl instead of using a chain of cp/cpc.
+ UseTest = true;
+ AVRcc = DAG.getConstant(AVRCC::COND_PL, DL, MVT::i8);
+ break;
+ }
+ case 0: {
+ // Turn lhs > 0 into 0 < lhs since 0 can be materialized with
+ // __zero_reg__ in lhs.
+ RHS = LHS;
+ LHS = DAG.getConstant(0, DL, VT);
+ CC = ISD::SETLT;
+ break;
+ }
+ default: {
+ // Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows
+ // us to fold the constant into the cmp instruction.
+ RHS = DAG.getConstant(C->getSExtValue() + 1, DL, VT);
+ CC = ISD::SETGE;
+ break;
+ }
+ }
+ break;
+ }
+ // Swap operands and reverse the branching condition.
+ std::swap(LHS, RHS);
+ CC = ISD::SETLT;
+ break;
+ }
+ case ISD::SETLT: {
+ if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
+ switch (C->getSExtValue()) {
+ case 1: {
+ // Turn lhs < 1 into 0 >= lhs since 0 can be materialized with
+ // __zero_reg__ in lhs.
+ RHS = LHS;
+ LHS = DAG.getConstant(0, DL, VT);
+ CC = ISD::SETGE;
+ break;
+ }
+ case 0: {
+ // When doing lhs < 0 use a tst instruction on the top part of lhs
+ // and use brmi instead of using a chain of cp/cpc.
+ UseTest = true;
+ AVRcc = DAG.getConstant(AVRCC::COND_MI, DL, MVT::i8);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case ISD::SETULE: {
+ // Swap operands and reverse the branching condition.
+ std::swap(LHS, RHS);
+ CC = ISD::SETUGE;
+ break;
+ }
+ case ISD::SETUGT: {
+ // Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows us to
+ // fold the constant into the cmp instruction.
+ if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
+ RHS = DAG.getConstant(C->getSExtValue() + 1, DL, VT);
+ CC = ISD::SETUGE;
+ break;
+ }
+ // Swap operands and reverse the branching condition.
+ std::swap(LHS, RHS);
+ CC = ISD::SETULT;
+ break;
+ }
+ }
+
+ // Expand 32 and 64 bit comparisons with custom CMP and CMPC nodes instead of
+ // using the default and/or/xor expansion code which is much longer.
+ if (VT == MVT::i32) {
+ SDValue LHSlo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue LHShi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS,
+ DAG.getIntPtrConstant(1, DL));
+ SDValue RHSlo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue RHShi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS,
+ DAG.getIntPtrConstant(1, DL));
+
+ if (UseTest) {
+ // When using tst we only care about the highest part.
+ SDValue Top = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHShi,
+ DAG.getIntPtrConstant(1, DL));
+ Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue, Top);
+ } else {
+ Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHSlo, RHSlo);
+ Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHShi, RHShi, Cmp);
+ }
+ } else if (VT == MVT::i64) {
+ SDValue LHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, LHS,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue LHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, LHS,
+ DAG.getIntPtrConstant(1, DL));
+
+ SDValue LHS0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_0,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue LHS1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_0,
+ DAG.getIntPtrConstant(1, DL));
+ SDValue LHS2 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_1,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue LHS3 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_1,
+ DAG.getIntPtrConstant(1, DL));
+
+ SDValue RHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, RHS,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue RHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, RHS,
+ DAG.getIntPtrConstant(1, DL));
+
+ SDValue RHS0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_0,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue RHS1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_0,
+ DAG.getIntPtrConstant(1, DL));
+ SDValue RHS2 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_1,
+ DAG.getIntPtrConstant(0, DL));
+ SDValue RHS3 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_1,
+ DAG.getIntPtrConstant(1, DL));
+
+ if (UseTest) {
+ // When using tst we only care about the highest part.
+ SDValue Top = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHS3,
+ DAG.getIntPtrConstant(1, DL));
+ Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue, Top);
+ } else {
+ Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHS0, RHS0);
+ Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS1, RHS1, Cmp);
+ Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS2, RHS2, Cmp);
+ Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS3, RHS3, Cmp);
+ }
+ } else if (VT == MVT::i8 || VT == MVT::i16) {
+ if (UseTest) {
+ // When using tst we only care about the highest part.
+ Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue,
+ (VT == MVT::i8)
+ ? LHS
+ : DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8,
+ LHS, DAG.getIntPtrConstant(1, DL)));
+ } else {
+ Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHS, RHS);
+ }
+ } else {
+ llvm_unreachable("Invalid comparison size");
+ }
+
+ // When using a test instruction AVRcc is already set.
+ if (!UseTest) {
+ AVRcc = DAG.getConstant(intCCToAVRCC(CC), DL, MVT::i8);
+ }
+
+ return Cmp;
+}
+
+SDValue AVRTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
+ SDValue Chain = Op.getOperand(0);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
+ SDValue LHS = Op.getOperand(2);
+ SDValue RHS = Op.getOperand(3);
+ SDValue Dest = Op.getOperand(4);
+ SDLoc dl(Op);
+
+ SDValue TargetCC;
+ SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, dl);
+
+ return DAG.getNode(AVRISD::BRCOND, dl, MVT::Other, Chain, Dest, TargetCC,
+ Cmp);
+}
+
+SDValue AVRTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
+ SDValue LHS = Op.getOperand(0);
+ SDValue RHS = Op.getOperand(1);
+ SDValue TrueV = Op.getOperand(2);
+ SDValue FalseV = Op.getOperand(3);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
+ SDLoc dl(Op);
+
+ SDValue TargetCC;
+ SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, dl);
+
+ SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
+ SDValue Ops[] = {TrueV, FalseV, TargetCC, Cmp};
+
+ return DAG.getNode(AVRISD::SELECT_CC, dl, VTs, Ops);
+}
+
+SDValue AVRTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
+ SDValue LHS = Op.getOperand(0);
+ SDValue RHS = Op.getOperand(1);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
+ SDLoc DL(Op);
+
+ SDValue TargetCC;
+ SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, DL);
+
+ SDValue TrueV = DAG.getConstant(1, DL, Op.getValueType());
+ SDValue FalseV = DAG.getConstant(0, DL, Op.getValueType());
+ SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
+ SDValue Ops[] = {TrueV, FalseV, TargetCC, Cmp};
+
+ return DAG.getNode(AVRISD::SELECT_CC, DL, VTs, Ops);
+}
+
+SDValue AVRTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const {
+ const MachineFunction &MF = DAG.getMachineFunction();
+ const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+ const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
+ auto DL = DAG.getDataLayout();
+ SDLoc dl(Op);
+
+ // Vastart just stores the address of the VarArgsFrameIndex slot into the
+ // memory location argument.
+ SDValue FI = DAG.getFrameIndex(AFI->getVarArgsFrameIndex(), getPointerTy(DL));
+
+ return DAG.getStore(Op.getOperand(0), dl, FI, Op.getOperand(1),
+ MachinePointerInfo(SV), 0);
+}
+
+SDValue AVRTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
+ switch (Op.getOpcode()) {
+ default:
+ llvm_unreachable("Don't know how to custom lower this!");
+ case ISD::SHL:
+ case ISD::SRA:
+ case ISD::SRL:
+ case ISD::ROTL:
+ case ISD::ROTR:
+ return LowerShifts(Op, DAG);
+ case ISD::GlobalAddress:
+ return LowerGlobalAddress(Op, DAG);
+ case ISD::BlockAddress:
+ return LowerBlockAddress(Op, DAG);
+ case ISD::BR_CC:
+ return LowerBR_CC(Op, DAG);
+ case ISD::SELECT_CC:
+ return LowerSELECT_CC(Op, DAG);
+ case ISD::SETCC:
+ return LowerSETCC(Op, DAG);
+ case ISD::VASTART:
+ return LowerVASTART(Op, DAG);
+ case ISD::SDIVREM:
+ case ISD::UDIVREM:
+ return LowerDivRem(Op, DAG);
+ }
+
+ return SDValue();
+}
+
+/// Replace a node with an illegal result type
+/// with a new node built out of custom code.
+void AVRTargetLowering::ReplaceNodeResults(SDNode *N,
+ SmallVectorImpl<SDValue> &Results,
+ SelectionDAG &DAG) const {
+ SDLoc DL(N);
+
+ switch (N->getOpcode()) {
+ case ISD::ADD: {
+ // Convert add (x, imm) into sub (x, -imm).
+ if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
+ SDValue Sub = DAG.getNode(
+ ISD::SUB, DL, N->getValueType(0), N->getOperand(0),
+ DAG.getConstant(-C->getAPIntValue(), DL, C->getValueType(0)));
+ Results.push_back(Sub);
+ }
+ break;
+ }
+ default: {
+ SDValue Res = LowerOperation(SDValue(N, 0), DAG);
+
+ for (unsigned I = 0, E = Res->getNumValues(); I != E; ++I)
+ Results.push_back(Res.getValue(I));
+
+ break;
+ }
+ }
+}
+
+/// Return true if the addressing mode represented
+/// by AM is legal for this target, for a load/store of the specified type.
+bool AVRTargetLowering::isLegalAddressingMode(const DataLayout &DL,
+ const AddrMode &AM, Type *Ty,
+ unsigned AS) const {
+ int64_t Offs = AM.BaseOffs;
+
+ // Allow absolute addresses.
+ if (AM.BaseGV && !AM.HasBaseReg && AM.Scale == 0 && Offs == 0) {
+ return true;
+ }
+
+ // Flash memory instructions only allow zero offsets.
+ if (isa<PointerType>(Ty) && AS == AVR::ProgramMemory) {
+ return false;
+ }
+
+ // Allow reg+<6bit> offset.
+ if (Offs < 0)
+ Offs = -Offs;
+ if (AM.BaseGV == 0 && AM.HasBaseReg && AM.Scale == 0 && isUInt<6>(Offs)) {
+ return true;
+ }
+
+ return false;
+}
+
+/// Returns true by value, base pointer and
+/// offset pointer and addressing mode by reference if the node's address
+/// can be legally represented as pre-indexed load / store address.
+bool AVRTargetLowering::getPreIndexedAddressParts(SDNode *N, SDValue &Base,
+ SDValue &Offset,
+ ISD::MemIndexedMode &AM,
+ SelectionDAG &DAG) const {
+ EVT VT;
+ const SDNode *Op;
+ SDLoc DL(N);
+
+ if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
+ VT = LD->getMemoryVT();
+ Op = LD->getBasePtr().getNode();
+ if (LD->getExtensionType() != ISD::NON_EXTLOAD)
+ return false;
+ if (AVR::isProgramMemoryAccess(LD)) {
+ return false;
+ }
+ } else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
+ VT = ST->getMemoryVT();
+ Op = ST->getBasePtr().getNode();
+ if (AVR::isProgramMemoryAccess(ST)) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ if (VT != MVT::i8 && VT != MVT::i16) {
+ return false;
+ }
+
+ if (Op->getOpcode() != ISD::ADD && Op->getOpcode() != ISD::SUB) {
+ return false;
+ }
+
+ if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1))) {
+ int RHSC = RHS->getSExtValue();
+ if (Op->getOpcode() == ISD::SUB)
+ RHSC = -RHSC;
+
+ if ((VT == MVT::i16 && RHSC != -2) || (VT == MVT::i8 && RHSC != -1)) {
+ return false;
+ }
+
+ Base = Op->getOperand(0);
+ Offset = DAG.getConstant(RHSC, DL, MVT::i8);
+ AM = ISD::PRE_DEC;
+
+ return true;
+ }
+
+ return false;
+}
+
+/// Returns true by value, base pointer and
+/// offset pointer and addressing mode by reference if this node can be
+/// combined with a load / store to form a post-indexed load / store.
+bool AVRTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
+ SDValue &Base,
+ SDValue &Offset,
+ ISD::MemIndexedMode &AM,
+ SelectionDAG &DAG) const {
+ EVT VT;
+ SDLoc DL(N);
+
+ if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
+ VT = LD->getMemoryVT();
+ if (LD->getExtensionType() != ISD::NON_EXTLOAD)
+ return false;
+ } else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
+ VT = ST->getMemoryVT();
+ if (AVR::isProgramMemoryAccess(ST)) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ if (VT != MVT::i8 && VT != MVT::i16) {
+ return false;
+ }
+
+ if (Op->getOpcode() != ISD::ADD && Op->getOpcode() != ISD::SUB) {
+ return false;
+ }
+
+ if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1))) {
+ int RHSC = RHS->getSExtValue();
+ if (Op->getOpcode() == ISD::SUB)
+ RHSC = -RHSC;
+ if ((VT == MVT::i16 && RHSC != 2) || (VT == MVT::i8 && RHSC != 1)) {
+ return false;
+ }
+
+ Base = Op->getOperand(0);
+ Offset = DAG.getConstant(RHSC, DL, MVT::i8);
+ AM = ISD::POST_INC;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool AVRTargetLowering::isOffsetFoldingLegal(
+ const GlobalAddressSDNode *GA) const {
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Formal Arguments Calling Convention Implementation
+//===----------------------------------------------------------------------===//
+
+#include "AVRGenCallingConv.inc"
+
+/// For each argument in a function store the number of pieces it is composed
+/// of.
+static void parseFunctionArgs(const Function *F, const DataLayout *TD,
+ SmallVectorImpl<unsigned> &Out) {
+ for (Argument const &Arg : F->args()) {
+ unsigned Bytes = (TD->getTypeSizeInBits(Arg.getType()) + 7) / 8;
+ Out.push_back((Bytes + 1) / 2);
+ }
+}
+
+/// For external symbols there is no function prototype information so we
+/// have to rely directly on argument sizes.
+static void parseExternFuncCallArgs(const SmallVectorImpl<ISD::OutputArg> &In,
+ SmallVectorImpl<unsigned> &Out) {
+ for (unsigned i = 0, e = In.size(); i != e;) {
+ unsigned Size = 0;
+ unsigned Offset = 0;
+ while ((i != e) && (In[i].PartOffset == Offset)) {
+ Offset += In[i].VT.getStoreSize();
+ ++i;
+ ++Size;
+ }
+ Out.push_back(Size);
+ }
+}
+
+static StringRef getFunctionName(TargetLowering::CallLoweringInfo &CLI) {
+ SDValue Callee = CLI.Callee;
+
+ if (const ExternalSymbolSDNode *G = dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ return G->getSymbol();
+ }
+
+ if (const GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ return G->getGlobal()->getName();
+ }
+
+ llvm_unreachable("don't know how to get the name for this callee");
+}
+
+/// Analyze incoming and outgoing function arguments. We need custom C++ code
+/// to handle special constraints in the ABI like reversing the order of the
+/// pieces of splitted arguments. In addition, all pieces of a certain argument
+/// have to be passed either using registers or the stack but never mixing both.
+static void analyzeStandardArguments(TargetLowering::CallLoweringInfo *CLI,
+ const Function *F, const DataLayout *TD,
+ const SmallVectorImpl<ISD::OutputArg> *Outs,
+ const SmallVectorImpl<ISD::InputArg> *Ins,
+ CallingConv::ID CallConv,
+ SmallVectorImpl<CCValAssign> &ArgLocs,
+ CCState &CCInfo, bool IsCall, bool IsVarArg) {
+ static const MCPhysReg RegList8[] = {AVR::R24, AVR::R22, AVR::R20,
+ AVR::R18, AVR::R16, AVR::R14,
+ AVR::R12, AVR::R10, AVR::R8};
+ static const MCPhysReg RegList16[] = {AVR::R25R24, AVR::R23R22, AVR::R21R20,
+ AVR::R19R18, AVR::R17R16, AVR::R15R14,
+ AVR::R13R12, AVR::R11R10, AVR::R9R8};
+ if (IsVarArg) {
+ // Variadic functions do not need all the analisys below.
+ if (IsCall) {
+ CCInfo.AnalyzeCallOperands(*Outs, ArgCC_AVR_Vararg);
+ } else {
+ CCInfo.AnalyzeFormalArguments(*Ins, ArgCC_AVR_Vararg);
+ }
+ return;
+ }
+
+ // Fill in the Args array which will contain original argument sizes.
+ SmallVector<unsigned, 8> Args;
+ if (IsCall) {
+ parseExternFuncCallArgs(*Outs, Args);
+ } else {
+ assert(F != nullptr && "function should not be null");
+ parseFunctionArgs(F, TD, Args);
+ }
+
+ unsigned RegsLeft = array_lengthof(RegList8), ValNo = 0;
+ // Variadic functions always use the stack.
+ bool UsesStack = false;
+ for (unsigned i = 0, pos = 0, e = Args.size(); i != e; ++i) {
+ unsigned Size = Args[i];
+ MVT LocVT = (IsCall) ? (*Outs)[pos].VT : (*Ins)[pos].VT;
+
+ // If we have plenty of regs to pass the whole argument do it.
+ if (!UsesStack && (Size <= RegsLeft)) {
+ const MCPhysReg *RegList = (LocVT == MVT::i16) ? RegList16 : RegList8;
+
+ for (unsigned j = 0; j != Size; ++j) {
+ unsigned Reg = CCInfo.AllocateReg(
+ ArrayRef<MCPhysReg>(RegList, array_lengthof(RegList8)));
+ CCInfo.addLoc(
+ CCValAssign::getReg(ValNo++, LocVT, Reg, LocVT, CCValAssign::Full));
+ --RegsLeft;
+ }
+
+ // Reverse the order of the pieces to agree with the "big endian" format
+ // required in the calling convention ABI.
+ std::reverse(ArgLocs.begin() + pos, ArgLocs.begin() + pos + Size);
+ } else {
+ // Pass the rest of arguments using the stack.
+ UsesStack = true;
+ for (unsigned j = 0; j != Size; ++j) {
+ unsigned Offset = CCInfo.AllocateStack(
+ TD->getTypeAllocSize(EVT(LocVT).getTypeForEVT(CCInfo.getContext())),
+ TD->getABITypeAlignment(
+ EVT(LocVT).getTypeForEVT(CCInfo.getContext())));
+ CCInfo.addLoc(CCValAssign::getMem(ValNo++, LocVT, Offset, LocVT,
+ CCValAssign::Full));
+ }
+ }
+ pos += Size;
+ }
+}
+
+static void analyzeBuiltinArguments(TargetLowering::CallLoweringInfo &CLI,
+ const Function *F, const DataLayout *TD,
+ const SmallVectorImpl<ISD::OutputArg> *Outs,
+ const SmallVectorImpl<ISD::InputArg> *Ins,
+ CallingConv::ID CallConv,
+ SmallVectorImpl<CCValAssign> &ArgLocs,
+ CCState &CCInfo, bool IsCall, bool IsVarArg) {
+ StringRef FuncName = getFunctionName(CLI);
+
+ if (FuncName.startswith("__udivmod") || FuncName.startswith("__divmod")) {
+ CCInfo.AnalyzeCallOperands(*Outs, ArgCC_AVR_BUILTIN_DIV);
+ } else {
+ analyzeStandardArguments(&CLI, F, TD, Outs, Ins,
+ CallConv, ArgLocs, CCInfo,
+ IsCall, IsVarArg);
+ }
+}
+
+static void analyzeArguments(TargetLowering::CallLoweringInfo *CLI,
+ const Function *F, const DataLayout *TD,
+ const SmallVectorImpl<ISD::OutputArg> *Outs,
+ const SmallVectorImpl<ISD::InputArg> *Ins,
+ CallingConv::ID CallConv,
+ SmallVectorImpl<CCValAssign> &ArgLocs,
+ CCState &CCInfo, bool IsCall, bool IsVarArg) {
+ switch (CallConv) {
+ case CallingConv::AVR_BUILTIN: {
+ analyzeBuiltinArguments(*CLI, F, TD, Outs, Ins,
+ CallConv, ArgLocs, CCInfo,
+ IsCall, IsVarArg);
+ return;
+ }
+ default: {
+ analyzeStandardArguments(CLI, F, TD, Outs, Ins,
+ CallConv, ArgLocs, CCInfo,
+ IsCall, IsVarArg);
+ return;
+ }
+ }
+}
+
+SDValue AVRTargetLowering::LowerFormalArguments(
+ SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ auto DL = DAG.getDataLayout();
+
+ // Assign locations to all of the incoming arguments.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
+ *DAG.getContext());
+
+ analyzeArguments(nullptr, MF.getFunction(), &DL, 0, &Ins, CallConv, ArgLocs, CCInfo,
+ false, isVarArg);
+
+ SDValue ArgValue;
+ for (CCValAssign &VA : ArgLocs) {
+
+ // Arguments stored on registers.
+ if (VA.isRegLoc()) {
+ EVT RegVT = VA.getLocVT();
+ const TargetRegisterClass *RC;
+ if (RegVT == MVT::i8) {
+ RC = &AVR::GPR8RegClass;
+ } else if (RegVT == MVT::i16) {
+ RC = &AVR::DREGSRegClass;
+ } else {
+ llvm_unreachable("Unknown argument type!");
+ }
+
+ unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC);
+ ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT);
+
+ // :NOTE: Clang should not promote any i8 into i16 but for safety the
+ // following code will handle zexts or sexts generated by other
+ // front ends. Otherwise:
+ // If this is an 8 bit value, it is really passed promoted
+ // to 16 bits. Insert an assert[sz]ext to capture this, then
+ // truncate to the right size.
+ switch (VA.getLocInfo()) {
+ default:
+ llvm_unreachable("Unknown loc info!");
+ case CCValAssign::Full:
+ break;
+ case CCValAssign::BCvt:
+ ArgValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), ArgValue);
+ break;
+ case CCValAssign::SExt:
+ ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue,
+ DAG.getValueType(VA.getValVT()));
+ ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
+ break;
+ case CCValAssign::ZExt:
+ ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue,
+ DAG.getValueType(VA.getValVT()));
+ ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
+ break;
+ }
+
+ InVals.push_back(ArgValue);
+ } else {
+ // Sanity check.
+ assert(VA.isMemLoc());
+
+ EVT LocVT = VA.getLocVT();
+
+ // Create the frame index object for this incoming parameter.
+ int FI = MFI.CreateFixedObject(LocVT.getSizeInBits() / 8,
+ VA.getLocMemOffset(), true);
+
+ // Create the SelectionDAG nodes corresponding to a load
+ // from this parameter.
+ SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DL));
+ InVals.push_back(DAG.getLoad(LocVT, dl, Chain, FIN,
+ MachinePointerInfo::getFixedStack(MF, FI),
+ 0));
+ }
+ }
+
+ // If the function takes variable number of arguments, make a frame index for
+ // the start of the first vararg value... for expansion of llvm.va_start.
+ if (isVarArg) {
+ unsigned StackSize = CCInfo.getNextStackOffset();
+ AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+
+ AFI->setVarArgsFrameIndex(MFI.CreateFixedObject(2, StackSize, true));
+ }
+
+ return Chain;
+}
+
+//===----------------------------------------------------------------------===//
+// Call Calling Convention Implementation
+//===----------------------------------------------------------------------===//
+
+SDValue AVRTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const {
+ SelectionDAG &DAG = CLI.DAG;
+ SDLoc &DL = CLI.DL;
+ SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
+ SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
+ SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
+ SDValue Chain = CLI.Chain;
+ SDValue Callee = CLI.Callee;
+ bool &isTailCall = CLI.IsTailCall;
+ CallingConv::ID CallConv = CLI.CallConv;
+ bool isVarArg = CLI.IsVarArg;
+
+ MachineFunction &MF = DAG.getMachineFunction();
+
+ // AVR does not yet support tail call optimization.
+ isTailCall = false;
+
+ // Analyze operands of the call, assigning locations to each operand.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
+ *DAG.getContext());
+
+ // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
+ // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
+ // node so that legalize doesn't hack it.
+ const Function *F = nullptr;
+ if (const GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ const GlobalValue *GV = G->getGlobal();
+
+ F = cast<Function>(GV);
+ Callee =
+ DAG.getTargetGlobalAddress(GV, DL, getPointerTy(DAG.getDataLayout()));
+ } else if (const ExternalSymbolSDNode *ES =
+ dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ Callee = DAG.getTargetExternalSymbol(ES->getSymbol(),
+ getPointerTy(DAG.getDataLayout()));
+ }
+
+ analyzeArguments(&CLI, F, &DAG.getDataLayout(), &Outs, 0, CallConv, ArgLocs, CCInfo,
+ true, isVarArg);
+
+ // Get a count of how many bytes are to be pushed on the stack.
+ unsigned NumBytes = CCInfo.getNextStackOffset();
+
+ Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(NumBytes, DL, true),
+ DL);
+
+ SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
+
+ // First, walk the register assignments, inserting copies.
+ unsigned AI, AE;
+ bool HasStackArgs = false;
+ for (AI = 0, AE = ArgLocs.size(); AI != AE; ++AI) {
+ CCValAssign &VA = ArgLocs[AI];
+ EVT RegVT = VA.getLocVT();
+ SDValue Arg = OutVals[AI];
+
+ // Promote the value if needed. With Clang this should not happen.
+ switch (VA.getLocInfo()) {
+ default:
+ llvm_unreachable("Unknown loc info!");
+ case CCValAssign::Full:
+ break;
+ case CCValAssign::SExt:
+ Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, RegVT, Arg);
+ break;
+ case CCValAssign::ZExt:
+ Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, RegVT, Arg);
+ break;
+ case CCValAssign::AExt:
+ Arg = DAG.getNode(ISD::ANY_EXTEND, DL, RegVT, Arg);
+ break;
+ case CCValAssign::BCvt:
+ Arg = DAG.getNode(ISD::BITCAST, DL, RegVT, Arg);
+ break;
+ }
+
+ // Stop when we encounter a stack argument, we need to process them
+ // in reverse order in the loop below.
+ if (VA.isMemLoc()) {
+ HasStackArgs = true;
+ break;
+ }
+
+ // Arguments that can be passed on registers must be kept in the RegsToPass
+ // vector.
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
+ }
+
+ // Second, stack arguments have to walked in reverse order by inserting
+ // chained stores, this ensures their order is not changed by the scheduler
+ // and that the push instruction sequence generated is correct, otherwise they
+ // can be freely intermixed.
+ if (HasStackArgs) {
+ for (AE = AI, AI = ArgLocs.size(); AI != AE; --AI) {
+ unsigned Loc = AI - 1;
+ CCValAssign &VA = ArgLocs[Loc];
+ SDValue Arg = OutVals[Loc];
+
+ assert(VA.isMemLoc());
+
+ // SP points to one stack slot further so add one to adjust it.
+ SDValue PtrOff = DAG.getNode(
+ ISD::ADD, DL, getPointerTy(DAG.getDataLayout()),
+ DAG.getRegister(AVR::SP, getPointerTy(DAG.getDataLayout())),
+ DAG.getIntPtrConstant(VA.getLocMemOffset() + 1, DL));
+
+ Chain =
+ DAG.getStore(Chain, DL, Arg, PtrOff,
+ MachinePointerInfo::getStack(MF, VA.getLocMemOffset()),
+ 0);
+ }
+ }
+
+ // Build a sequence of copy-to-reg nodes chained together with token chain and
+ // flag operands which copy the outgoing args into registers. The InFlag in
+ // necessary since all emited instructions must be stuck together.
+ SDValue InFlag;
+ for (auto Reg : RegsToPass) {
+ Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, InFlag);
+ InFlag = Chain.getValue(1);
+ }
+
+ // Returns a chain & a flag for retval copy to use.
+ SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
+ SmallVector<SDValue, 8> Ops;
+ Ops.push_back(Chain);
+ Ops.push_back(Callee);
+
+ // Add argument registers to the end of the list so that they are known live
+ // into the call.
+ for (auto Reg : RegsToPass) {
+ Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
+ }
+
+ // Add a register mask operand representing the call-preserved registers.
+ const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
+ const TargetRegisterInfo *TRI = TM.getSubtargetImpl()->getRegisterInfo();
+ const uint32_t *Mask =
+ TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv);
+ assert(Mask && "Missing call preserved mask for calling convention");
+ Ops.push_back(DAG.getRegisterMask(Mask));
+
+ if (InFlag.getNode()) {
+ Ops.push_back(InFlag);
+ }
+
+ Chain = DAG.getNode(AVRISD::CALL, DL, NodeTys, Ops);
+ InFlag = Chain.getValue(1);
+
+ // Create the CALLSEQ_END node.
+ Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, DL, true),
+ DAG.getIntPtrConstant(0, DL, true), InFlag, DL);
+
+ if (!Ins.empty()) {
+ InFlag = Chain.getValue(1);
+ }
+
+ // Handle result values, copying them out of physregs into vregs that we
+ // return.
+ return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins, DL, DAG,
+ InVals);
+}
+
+/// Lower the result values of a call into the
+/// appropriate copies out of appropriate physical registers.
+///
+SDValue AVRTargetLowering::LowerCallResult(
+ SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const {
+
+ // Assign locations to each value returned by this call.
+ SmallVector<CCValAssign, 16> RVLocs;
+ CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,
+ *DAG.getContext());
+
+ // Handle runtime calling convs.
+ auto CCFunction = CCAssignFnForReturn(CallConv);
+ CCInfo.AnalyzeCallResult(Ins, CCFunction);
+
+ if (CallConv != CallingConv::AVR_BUILTIN && RVLocs.size() > 1) {
+ // Reverse splitted return values to get the "big endian" format required
+ // to agree with the calling convention ABI.
+ std::reverse(RVLocs.begin(), RVLocs.end());
+ }
+
+ // Copy all of the result registers out of their specified physreg.
+ for (CCValAssign const &RVLoc : RVLocs) {
+ Chain = DAG.getCopyFromReg(Chain, dl, RVLoc.getLocReg(), RVLoc.getValVT(),
+ InFlag)
+ .getValue(1);
+ InFlag = Chain.getValue(2);
+ InVals.push_back(Chain.getValue(0));
+ }
+
+ return Chain;
+}
+
+//===----------------------------------------------------------------------===//
+// Return Value Calling Convention Implementation
+//===----------------------------------------------------------------------===//
+
+CCAssignFn *AVRTargetLowering::CCAssignFnForReturn(CallingConv::ID CC) const {
+ switch (CC) {
+ case CallingConv::AVR_BUILTIN:
+ return RetCC_AVR_BUILTIN;
+ default:
+ return RetCC_AVR;
+ }
+}
+
+bool
+AVRTargetLowering::CanLowerReturn(CallingConv::ID CallConv,
+ MachineFunction &MF, bool isVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ LLVMContext &Context) const
+{
+ SmallVector<CCValAssign, 16> RVLocs;
+ CCState CCInfo(CallConv, isVarArg, MF, RVLocs, Context);
+
+ auto CCFunction = CCAssignFnForReturn(CallConv);
+ return CCInfo.CheckReturn(Outs, CCFunction);
+}
+
+SDValue
+AVRTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
+ bool isVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals,
+ const SDLoc &dl, SelectionDAG &DAG) const {
+ // CCValAssign - represent the assignment of the return value to locations.
+ SmallVector<CCValAssign, 16> RVLocs;
+
+ // CCState - Info about the registers and stack slot.
+ CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,
+ *DAG.getContext());
+
+ // Analyze return values.
+ auto CCFunction = CCAssignFnForReturn(CallConv);
+ CCInfo.AnalyzeReturn(Outs, CCFunction);
+
+ // If this is the first return lowered for this function, add the regs to
+ // the liveout set for the function.
+ MachineFunction &MF = DAG.getMachineFunction();
+ unsigned e = RVLocs.size();
+
+ // Reverse splitted return values to get the "big endian" format required
+ // to agree with the calling convention ABI.
+ if (e > 1) {
+ std::reverse(RVLocs.begin(), RVLocs.end());
+ }
+
+ SDValue Flag;
+ SmallVector<SDValue, 4> RetOps(1, Chain);
+ // Copy the result values into the output registers.
+ for (unsigned i = 0; i != e; ++i) {
+ CCValAssign &VA = RVLocs[i];
+ assert(VA.isRegLoc() && "Can only return in registers!");
+
+ Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Flag);
+
+ // Guarantee that all emitted copies are stuck together with flags.
+ Flag = Chain.getValue(1);
+ RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
+ }
+
+ // Don't emit the ret/reti instruction when the naked attribute is present in
+ // the function being compiled.
+ if (MF.getFunction()->getAttributes().hasAttribute(
+ AttributeSet::FunctionIndex, Attribute::Naked)) {
+ return Chain;
+ }
+
+ unsigned RetOpc =
+ (CallConv == CallingConv::AVR_INTR || CallConv == CallingConv::AVR_SIGNAL)
+ ? AVRISD::RETI_FLAG
+ : AVRISD::RET_FLAG;
+
+ RetOps[0] = Chain; // Update chain.
+
+ if (Flag.getNode()) {
+ RetOps.push_back(Flag);
+ }
+
+ return DAG.getNode(RetOpc, dl, MVT::Other, RetOps);
+}
+
+//===----------------------------------------------------------------------===//
+// Custom Inserters
+//===----------------------------------------------------------------------===//
+
+MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
+ MachineBasicBlock *BB) const {
+ unsigned Opc;
+ const TargetRegisterClass *RC;
+ MachineFunction *F = BB->getParent();
+ MachineRegisterInfo &RI = F->getRegInfo();
+ const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
+ const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
+ DebugLoc dl = MI.getDebugLoc();
+
+ switch (MI.getOpcode()) {
+ default:
+ llvm_unreachable("Invalid shift opcode!");
+ case AVR::Lsl8:
+ Opc = AVR::LSLRd;
+ RC = &AVR::GPR8RegClass;
+ break;
+ case AVR::Lsl16:
+ Opc = AVR::LSLWRd;
+ RC = &AVR::DREGSRegClass;
+ break;
+ case AVR::Asr8:
+ Opc = AVR::ASRRd;
+ RC = &AVR::GPR8RegClass;
+ break;
+ case AVR::Asr16:
+ Opc = AVR::ASRWRd;
+ RC = &AVR::DREGSRegClass;
+ break;
+ case AVR::Lsr8:
+ Opc = AVR::LSRRd;
+ RC = &AVR::GPR8RegClass;
+ break;
+ case AVR::Lsr16:
+ Opc = AVR::LSRWRd;
+ RC = &AVR::DREGSRegClass;
+ break;
+ }
+
+ const BasicBlock *LLVM_BB = BB->getBasicBlock();
+ MachineFunction::iterator I = BB->getParent()->begin();
+ ++I;
+
+ // Create loop block.
+ MachineBasicBlock *LoopBB = F->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *RemBB = F->CreateMachineBasicBlock(LLVM_BB);
+
+ F->insert(I, LoopBB);
+ F->insert(I, RemBB);
+
+ // Update machine-CFG edges by transferring all successors of the current
+ // block to the block containing instructions after shift.
+ RemBB->splice(RemBB->begin(), BB, std::next(MachineBasicBlock::iterator(MI)),
+ BB->end());
+ RemBB->transferSuccessorsAndUpdatePHIs(BB);
+
+ // Add adges BB => LoopBB => RemBB, BB => RemBB, LoopBB => LoopBB.
+ BB->addSuccessor(LoopBB);
+ BB->addSuccessor(RemBB);
+ LoopBB->addSuccessor(RemBB);
+ LoopBB->addSuccessor(LoopBB);
+
+ unsigned ShiftAmtReg = RI.createVirtualRegister(&AVR::LD8RegClass);
+ unsigned ShiftAmtReg2 = RI.createVirtualRegister(&AVR::LD8RegClass);
+ unsigned ShiftReg = RI.createVirtualRegister(RC);
+ unsigned ShiftReg2 = RI.createVirtualRegister(RC);
+ unsigned ShiftAmtSrcReg = MI.getOperand(2).getReg();
+ unsigned SrcReg = MI.getOperand(1).getReg();
+ unsigned DstReg = MI.getOperand(0).getReg();
+
+ // BB:
+ // cp 0, N
+ // breq RemBB
+ BuildMI(BB, dl, TII.get(AVR::CPRdRr)).addReg(ShiftAmtSrcReg).addReg(AVR::R0);
+ BuildMI(BB, dl, TII.get(AVR::BREQk)).addMBB(RemBB);
+
+ // LoopBB:
+ // ShiftReg = phi [%SrcReg, BB], [%ShiftReg2, LoopBB]
+ // ShiftAmt = phi [%N, BB], [%ShiftAmt2, LoopBB]
+ // ShiftReg2 = shift ShiftReg
+ // ShiftAmt2 = ShiftAmt - 1;
+ BuildMI(LoopBB, dl, TII.get(AVR::PHI), ShiftReg)
+ .addReg(SrcReg)
+ .addMBB(BB)
+ .addReg(ShiftReg2)
+ .addMBB(LoopBB);
+ BuildMI(LoopBB, dl, TII.get(AVR::PHI), ShiftAmtReg)
+ .addReg(ShiftAmtSrcReg)
+ .addMBB(BB)
+ .addReg(ShiftAmtReg2)
+ .addMBB(LoopBB);
+ BuildMI(LoopBB, dl, TII.get(Opc), ShiftReg2).addReg(ShiftReg);
+ BuildMI(LoopBB, dl, TII.get(AVR::SUBIRdK), ShiftAmtReg2)
+ .addReg(ShiftAmtReg)
+ .addImm(1);
+ BuildMI(LoopBB, dl, TII.get(AVR::BRNEk)).addMBB(LoopBB);
+
+ // RemBB:
+ // DestReg = phi [%SrcReg, BB], [%ShiftReg, LoopBB]
+ BuildMI(*RemBB, RemBB->begin(), dl, TII.get(AVR::PHI), DstReg)
+ .addReg(SrcReg)
+ .addMBB(BB)
+ .addReg(ShiftReg2)
+ .addMBB(LoopBB);
+
+ MI.eraseFromParent(); // The pseudo instruction is gone now.
+ return RemBB;
+}
+
+static bool isCopyMulResult(MachineBasicBlock::iterator const &I) {
+ if (I->getOpcode() == AVR::COPY) {
+ unsigned SrcReg = I->getOperand(1).getReg();
+ return (SrcReg == AVR::R0 || SrcReg == AVR::R1);
+ }
+
+ return false;
+}
+
+// The mul instructions wreak havock on our zero_reg R1. We need to clear it
+// after the result has been evacuated. This is probably not the best way to do
+// it, but it works for now.
+MachineBasicBlock *AVRTargetLowering::insertMul(MachineInstr &MI,
+ MachineBasicBlock *BB) const {
+ const AVRTargetMachine &TM = (const AVRTargetMachine &)getTargetMachine();
+ const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
+ MachineBasicBlock::iterator I(MI);
+ ++I; // in any case insert *after* the mul instruction
+ if (isCopyMulResult(I))
+ ++I;
+ if (isCopyMulResult(I))
+ ++I;
+ BuildMI(*BB, I, MI.getDebugLoc(), TII.get(AVR::EORRdRr), AVR::R1)
+ .addReg(AVR::R1)
+ .addReg(AVR::R1);
+ return BB;
+}
+
+MachineBasicBlock *
+AVRTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
+ MachineBasicBlock *MBB) const {
+ int Opc = MI.getOpcode();
+
+ // Pseudo shift instructions with a non constant shift amount are expanded
+ // into a loop.
+ switch (Opc) {
+ case AVR::Lsl8:
+ case AVR::Lsl16:
+ case AVR::Lsr8:
+ case AVR::Lsr16:
+ case AVR::Asr8:
+ case AVR::Asr16:
+ return insertShift(MI, MBB);
+ case AVR::MULRdRr:
+ case AVR::MULSRdRr:
+ return insertMul(MI, MBB);
+ }
+
+ assert((Opc == AVR::Select16 || Opc == AVR::Select8) &&
+ "Unexpected instr type to insert");
+
+ const AVRInstrInfo &TII = (const AVRInstrInfo &)*MI.getParent()
+ ->getParent()
+ ->getSubtarget()
+ .getInstrInfo();
+ DebugLoc dl = MI.getDebugLoc();
+
+ // To "insert" a SELECT instruction, we insert the diamond
+ // control-flow pattern. The incoming instruction knows the
+ // destination vreg to set, the condition code register to branch
+ // on, the true/false values to select between, and a branch opcode
+ // to use.
+
+ MachineFunction *MF = MBB->getParent();
+ const BasicBlock *LLVM_BB = MBB->getBasicBlock();
+ MachineBasicBlock *trueMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *falseMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+
+ MachineFunction::iterator I = MBB->getParent()->begin();
+ ++I;
+ MF->insert(I, trueMBB);
+ MF->insert(I, falseMBB);
+
+ // Transfer remaining instructions and all successors of the current
+ // block to the block which will contain the Phi node for the
+ // select.
+ trueMBB->splice(trueMBB->begin(), MBB,
+ std::next(MachineBasicBlock::iterator(MI)), MBB->end());
+ trueMBB->transferSuccessorsAndUpdatePHIs(MBB);
+
+ AVRCC::CondCodes CC = (AVRCC::CondCodes)MI.getOperand(3).getImm();
+ BuildMI(MBB, dl, TII.getBrCond(CC)).addMBB(trueMBB);
+ BuildMI(MBB, dl, TII.get(AVR::RJMPk)).addMBB(falseMBB);
+ MBB->addSuccessor(falseMBB);
+ MBB->addSuccessor(trueMBB);
+
+ // Unconditionally flow back to the true block
+ BuildMI(falseMBB, dl, TII.get(AVR::RJMPk)).addMBB(trueMBB);
+ falseMBB->addSuccessor(trueMBB);
+
+ // Set up the Phi node to determine where we came from
+ BuildMI(*trueMBB, trueMBB->begin(), dl, TII.get(AVR::PHI), MI.getOperand(0).getReg())
+ .addReg(MI.getOperand(1).getReg())
+ .addMBB(MBB)
+ .addReg(MI.getOperand(2).getReg())
+ .addMBB(falseMBB) ;
+
+ MI.eraseFromParent(); // The pseudo instruction is gone now.
+ return trueMBB;
+}
+
+//===----------------------------------------------------------------------===//
+// Inline Asm Support
+//===----------------------------------------------------------------------===//
+
+AVRTargetLowering::ConstraintType
+AVRTargetLowering::getConstraintType(StringRef Constraint) const {
+ if (Constraint.size() == 1) {
+ // See http://www.nongnu.org/avr-libc/user-manual/inline_asm.html
+ switch (Constraint[0]) {
+ case 'a': // Simple upper registers
+ case 'b': // Base pointer registers pairs
+ case 'd': // Upper register
+ case 'l': // Lower registers
+ case 'e': // Pointer register pairs
+ case 'q': // Stack pointer register
+ case 'r': // Any register
+ case 'w': // Special upper register pairs
+ return C_RegisterClass;
+ case 't': // Temporary register
+ case 'x': case 'X': // Pointer register pair X
+ case 'y': case 'Y': // Pointer register pair Y
+ case 'z': case 'Z': // Pointer register pair Z
+ return C_Register;
+ case 'Q': // A memory address based on Y or Z pointer with displacement.
+ return C_Memory;
+ case 'G': // Floating point constant
+ case 'I': // 6-bit positive integer constant
+ case 'J': // 6-bit negative integer constant
+ case 'K': // Integer constant (Range: 2)
+ case 'L': // Integer constant (Range: 0)
+ case 'M': // 8-bit integer constant
+ case 'N': // Integer constant (Range: -1)
+ case 'O': // Integer constant (Range: 8, 16, 24)
+ case 'P': // Integer constant (Range: 1)
+ case 'R': // Integer constant (Range: -6 to 5)x
+ return C_Other;
+ default:
+ break;
+ }
+ }
+
+ return TargetLowering::getConstraintType(Constraint);
+}
+
+unsigned
+AVRTargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const {
+ // Not sure if this is actually the right thing to do, but we got to do
+ // *something* [agnat]
+ switch (ConstraintCode[0]) {
+ case 'Q':
+ return InlineAsm::Constraint_Q;
+ }
+ return TargetLowering::getInlineAsmMemConstraint(ConstraintCode);
+}
+
+AVRTargetLowering::ConstraintWeight
+AVRTargetLowering::getSingleConstraintMatchWeight(
+ AsmOperandInfo &info, const char *constraint) const {
+ ConstraintWeight weight = CW_Invalid;
+ Value *CallOperandVal = info.CallOperandVal;
+
+ // If we don't have a value, we can't do a match,
+ // but allow it at the lowest weight.
+ // (this behaviour has been copied from the ARM backend)
+ if (!CallOperandVal) {
+ return CW_Default;
+ }
+
+ // Look at the constraint type.
+ switch (*constraint) {
+ default:
+ weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint);
+ break;
+ case 'd':
+ case 'r':
+ case 'l':
+ weight = CW_Register;
+ break;
+ case 'a':
+ case 'b':
+ case 'e':
+ case 'q':
+ case 't':
+ case 'w':
+ case 'x': case 'X':
+ case 'y': case 'Y':
+ case 'z': case 'Z':
+ weight = CW_SpecificReg;
+ break;
+ case 'G':
+ if (const ConstantFP *C = dyn_cast<ConstantFP>(CallOperandVal)) {
+ if (C->isZero()) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'I':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (isUInt<6>(C->getZExtValue())) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'J':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if ((C->getSExtValue() >= -63) && (C->getSExtValue() <= 0)) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'K':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (C->getZExtValue() == 2) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'L':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (C->getZExtValue() == 0) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'M':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (isUInt<8>(C->getZExtValue())) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'N':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (C->getSExtValue() == -1) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'O':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if ((C->getZExtValue() == 8) || (C->getZExtValue() == 16) ||
+ (C->getZExtValue() == 24)) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'P':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if (C->getZExtValue() == 1) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'R':
+ if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
+ if ((C->getSExtValue() >= -6) && (C->getSExtValue() <= 5)) {
+ weight = CW_Constant;
+ }
+ }
+ break;
+ case 'Q':
+ weight = CW_Memory;
+ break;
+ }
+
+ return weight;
+}
+
+std::pair<unsigned, const TargetRegisterClass *>
+AVRTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
+ StringRef Constraint,
+ MVT VT) const {
+ auto STI = static_cast<const AVRTargetMachine &>(this->getTargetMachine())
+ .getSubtargetImpl();
+
+ // We only support i8 and i16.
+ //
+ //:FIXME: remove this assert for now since it gets sometimes executed
+ // assert((VT == MVT::i16 || VT == MVT::i8) && "Wrong operand type.");
+
+ if (Constraint.size() == 1) {
+ switch (Constraint[0]) {
+ case 'a': // Simple upper registers r16..r23.
+ return std::make_pair(0U, &AVR::LD8loRegClass);
+ case 'b': // Base pointer registers: y, z.
+ return std::make_pair(0U, &AVR::PTRDISPREGSRegClass);
+ case 'd': // Upper registers r16..r31.
+ return std::make_pair(0U, &AVR::LD8RegClass);
+ case 'l': // Lower registers r0..r15.
+ return std::make_pair(0U, &AVR::GPR8loRegClass);
+ case 'e': // Pointer register pairs: x, y, z.
+ return std::make_pair(0U, &AVR::PTRREGSRegClass);
+ case 'q': // Stack pointer register: SPH:SPL.
+ return std::make_pair(0U, &AVR::GPRSPRegClass);
+ case 'r': // Any register: r0..r31.
+ if (VT == MVT::i8)
+ return std::make_pair(0U, &AVR::GPR8RegClass);
+
+ assert(VT == MVT::i16 && "inline asm constraint too large");
+ return std::make_pair(0U, &AVR::DREGSRegClass);
+ case 't': // Temporary register: r0.
+ return std::make_pair(unsigned(AVR::R0), &AVR::GPR8RegClass);
+ case 'w': // Special upper register pairs: r24, r26, r28, r30.
+ return std::make_pair(0U, &AVR::IWREGSRegClass);
+ case 'x': // Pointer register pair X: r27:r26.
+ case 'X':
+ return std::make_pair(unsigned(AVR::R27R26), &AVR::PTRREGSRegClass);
+ case 'y': // Pointer register pair Y: r29:r28.
+ case 'Y':
+ return std::make_pair(unsigned(AVR::R29R28), &AVR::PTRREGSRegClass);
+ case 'z': // Pointer register pair Z: r31:r30.
+ case 'Z':
+ return std::make_pair(unsigned(AVR::R31R30), &AVR::PTRREGSRegClass);
+ default:
+ break;
+ }
+ }
+
+ return TargetLowering::getRegForInlineAsmConstraint(STI->getRegisterInfo(),
+ Constraint, VT);
+}
+
+void AVRTargetLowering::LowerAsmOperandForConstraint(SDValue Op,
+ std::string &Constraint,
+ std::vector<SDValue> &Ops,
+ SelectionDAG &DAG) const {
+ SDValue Result(0, 0);
+ SDLoc DL(Op);
+ EVT Ty = Op.getValueType();
+
+ // Currently only support length 1 constraints.
+ if (Constraint.length() != 1) {
+ return;
+ }
+
+ char ConstraintLetter = Constraint[0];
+ switch (ConstraintLetter) {
+ default:
+ break;
+ // Deal with integers first:
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'R': {
+ const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op);
+ if (!C) {
+ return;
+ }
+
+ int64_t CVal64 = C->getSExtValue();
+ uint64_t CUVal64 = C->getZExtValue();
+ switch (ConstraintLetter) {
+ case 'I': // 0..63
+ if (!isUInt<6>(CUVal64))
+ return;
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'J': // -63..0
+ if (CVal64 < -63 || CVal64 > 0)
+ return;
+ Result = DAG.getTargetConstant(CVal64, DL, Ty);
+ break;
+ case 'K': // 2
+ if (CUVal64 != 2)
+ return;
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'L': // 0
+ if (CUVal64 != 0)
+ return;
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'M': // 0..255
+ if (!isUInt<8>(CUVal64))
+ return;
+ // i8 type may be printed as a negative number,
+ // e.g. 254 would be printed as -2,
+ // so we force it to i16 at least.
+ if (Ty.getSimpleVT() == MVT::i8) {
+ Ty = MVT::i16;
+ }
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'N': // -1
+ if (CVal64 != -1)
+ return;
+ Result = DAG.getTargetConstant(CVal64, DL, Ty);
+ break;
+ case 'O': // 8, 16, 24
+ if (CUVal64 != 8 && CUVal64 != 16 && CUVal64 != 24)
+ return;
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'P': // 1
+ if (CUVal64 != 1)
+ return;
+ Result = DAG.getTargetConstant(CUVal64, DL, Ty);
+ break;
+ case 'R': // -6..5
+ if (CVal64 < -6 || CVal64 > 5)
+ return;
+ Result = DAG.getTargetConstant(CVal64, DL, Ty);
+ break;
+ }
+
+ break;
+ }
+ case 'G':
+ const ConstantFPSDNode *FC = dyn_cast<ConstantFPSDNode>(Op);
+ if (!FC || !FC->isZero())
+ return;
+ // Soften float to i8 0
+ Result = DAG.getTargetConstant(0, DL, MVT::i8);
+ break;
+ }
+
+ if (Result.getNode()) {
+ Ops.push_back(Result);
+ return;
+ }
+
+ return TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
+}
+
+unsigned AVRTargetLowering::getRegisterByName(const char *RegName,
+ EVT VT,
+ SelectionDAG &DAG) const {
+ unsigned Reg;
+
+ if (VT == MVT::i8) {
+ Reg = StringSwitch<unsigned>(RegName)
+ .Case("r0", AVR::R0).Case("r1", AVR::R1).Case("r2", AVR::R2)
+ .Case("r3", AVR::R3).Case("r4", AVR::R4).Case("r5", AVR::R5)
+ .Case("r6", AVR::R6).Case("r7", AVR::R7).Case("r8", AVR::R8)
+ .Case("r9", AVR::R9).Case("r10", AVR::R10).Case("r11", AVR::R11)
+ .Case("r12", AVR::R12).Case("r13", AVR::R13).Case("r14", AVR::R14)
+ .Case("r15", AVR::R15).Case("r16", AVR::R16).Case("r17", AVR::R17)
+ .Case("r18", AVR::R18).Case("r19", AVR::R19).Case("r20", AVR::R20)
+ .Case("r21", AVR::R21).Case("r22", AVR::R22).Case("r23", AVR::R23)
+ .Case("r24", AVR::R24).Case("r25", AVR::R25).Case("r26", AVR::R26)
+ .Case("r27", AVR::R27).Case("r28", AVR::R28).Case("r29", AVR::R29)
+ .Case("r30", AVR::R30).Case("r31", AVR::R31)
+ .Case("X", AVR::R27R26).Case("Y", AVR::R29R28).Case("Z", AVR::R31R30)
+ .Default(0);
+ } else {
+ Reg = StringSwitch<unsigned>(RegName)
+ .Case("r0", AVR::R1R0).Case("r2", AVR::R3R2)
+ .Case("r4", AVR::R5R4).Case("r6", AVR::R7R6)
+ .Case("r8", AVR::R9R8).Case("r10", AVR::R11R10)
+ .Case("r12", AVR::R13R12).Case("r14", AVR::R15R14)
+ .Case("r16", AVR::R17R16).Case("r18", AVR::R19R18)
+ .Case("r20", AVR::R21R20).Case("r22", AVR::R23R22)
+ .Case("r24", AVR::R25R24).Case("r26", AVR::R27R26)
+ .Case("r28", AVR::R29R28).Case("r30", AVR::R31R30)
+ .Case("X", AVR::R27R26).Case("Y", AVR::R29R28).Case("Z", AVR::R31R30)
+ .Default(0);
+ }
+
+ if (Reg)
+ return Reg;
+
+ report_fatal_error("Invalid register name global variable");
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRISelLowering.h b/contrib/llvm/lib/Target/AVR/AVRISelLowering.h
index 2c8c9c8..a8cdc4e 100644
--- a/contrib/llvm/lib/Target/AVR/AVRISelLowering.h
+++ b/contrib/llvm/lib/Target/AVR/AVRISelLowering.h
@@ -15,6 +15,7 @@
#ifndef LLVM_AVR_ISEL_LOWERING_H
#define LLVM_AVR_ISEL_LOWERING_H
+#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/Target/TargetLowering.h"
namespace llvm {
@@ -92,6 +93,9 @@ public:
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
+ EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context,
+ EVT VT) const override;
+
MachineBasicBlock *
EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *MBB) const override;
@@ -112,6 +116,9 @@ public:
std::vector<SDValue> &Ops,
SelectionDAG &DAG) const override;
+ unsigned getRegisterByName(const char* RegName, EVT VT,
+ SelectionDAG &DAG) const override;
+
private:
SDValue getAVRCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue &AVRcc,
SelectionDAG &DAG, SDLoc dl) const;
@@ -125,6 +132,13 @@ private:
SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
+ CCAssignFn *CCAssignFnForReturn(CallingConv::ID CC) const;
+
+ bool CanLowerReturn(CallingConv::ID CallConv,
+ MachineFunction &MF, bool isVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ LLVMContext &Context) const override;
+
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals, const SDLoc &dl,
@@ -143,8 +157,8 @@ private:
SmallVectorImpl<SDValue> &InVals) const;
private:
- MachineBasicBlock *insertShift(MachineInstr *MI, MachineBasicBlock *BB) const;
- MachineBasicBlock *insertMul(MachineInstr *MI, MachineBasicBlock *BB) const;
+ MachineBasicBlock *insertShift(MachineInstr &MI, MachineBasicBlock *BB) const;
+ MachineBasicBlock *insertMul(MachineInstr &MI, MachineBasicBlock *BB) const;
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRInstrFormats.td b/contrib/llvm/lib/Target/AVR/AVRInstrFormats.td
index c10023d..ce5e606 100644
--- a/contrib/llvm/lib/Target/AVR/AVRInstrFormats.td
+++ b/contrib/llvm/lib/Target/AVR/AVRInstrFormats.td
@@ -20,6 +20,8 @@ class AVRInst<dag outs, dag ins, string asmstr, list<dag> pattern> : Instruction
dag InOperandList = ins;
let AsmString = asmstr;
let Pattern = pattern;
+
+ field bits<32> SoftFail = 0;
}
/// A 16-bit AVR instruction.
diff --git a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.cpp b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.cpp
index 0327c01..88f8892 100644
--- a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.cpp
+++ b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.cpp
@@ -27,6 +27,7 @@
#include "AVR.h"
#include "AVRMachineFunctionInfo.h"
+#include "AVRRegisterInfo.h"
#include "AVRTargetMachine.h"
#include "MCTargetDesc/AVRMCTargetDesc.h"
@@ -42,22 +43,41 @@ void AVRInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const DebugLoc &DL, unsigned DestReg,
unsigned SrcReg, bool KillSrc) const {
+ const AVRSubtarget &STI = MBB.getParent()->getSubtarget<AVRSubtarget>();
+ const AVRRegisterInfo &TRI = *STI.getRegisterInfo();
unsigned Opc;
- if (AVR::GPR8RegClass.contains(DestReg, SrcReg)) {
- Opc = AVR::MOVRdRr;
- } else if (AVR::DREGSRegClass.contains(DestReg, SrcReg)) {
- Opc = AVR::MOVWRdRr;
- } else if (SrcReg == AVR::SP && AVR::DREGSRegClass.contains(DestReg)) {
- Opc = AVR::SPREAD;
- } else if (DestReg == AVR::SP && AVR::DREGSRegClass.contains(SrcReg)) {
- Opc = AVR::SPWRITE;
+ // Not all AVR devices support the 16-bit `MOVW` instruction.
+ if (AVR::DREGSRegClass.contains(DestReg, SrcReg)) {
+ if (STI.hasMOVW()) {
+ BuildMI(MBB, MI, DL, get(AVR::MOVWRdRr), DestReg)
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ } else {
+ unsigned DestLo, DestHi, SrcLo, SrcHi;
+
+ TRI.splitReg(DestReg, DestLo, DestHi);
+ TRI.splitReg(SrcReg, SrcLo, SrcHi);
+
+ // Copy each individual register with the `MOV` instruction.
+ BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestLo)
+ .addReg(SrcLo, getKillRegState(KillSrc));
+ BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestHi)
+ .addReg(SrcHi, getKillRegState(KillSrc));
+ }
} else {
- llvm_unreachable("Impossible reg-to-reg copy");
- }
+ if (AVR::GPR8RegClass.contains(DestReg, SrcReg)) {
+ Opc = AVR::MOVRdRr;
+ } else if (SrcReg == AVR::SP && AVR::DREGSRegClass.contains(DestReg)) {
+ Opc = AVR::SPREAD;
+ } else if (DestReg == AVR::SP && AVR::DREGSRegClass.contains(SrcReg)) {
+ Opc = AVR::SPWRITE;
+ } else {
+ llvm_unreachable("Impossible reg-to-reg copy");
+ }
- BuildMI(MBB, MI, DL, get(Opc), DestReg)
- .addReg(SrcReg, getKillRegState(KillSrc));
+ BuildMI(MBB, MI, DL, get(Opc), DestReg)
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ }
}
unsigned AVRInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
@@ -105,13 +125,16 @@ void AVRInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
MachineFunction &MF = *MBB.getParent();
+ AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+
+ AFI->setHasSpills(true);
DebugLoc DL;
if (MI != MBB.end()) {
DL = MI->getDebugLoc();
}
- const MachineFrameInfo &MFI = *MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FrameIndex),
@@ -145,7 +168,7 @@ void AVRInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
}
MachineFunction &MF = *MBB.getParent();
- const MachineFrameInfo &MFI = *MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FrameIndex),
@@ -373,13 +396,16 @@ bool AVRInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
return false;
}
-unsigned AVRInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+unsigned AVRInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const {
+ const DebugLoc &DL,
+ int *BytesAdded) const {
+ assert(!BytesAdded && "code size not handled");
+
// Shouldn't be a fall through.
- assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert(TBB && "insertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 1 || Cond.size() == 0) &&
"AVR branch conditions have one component!");
@@ -404,7 +430,10 @@ unsigned AVRInstrInfo::InsertBranch(MachineBasicBlock &MBB,
return Count;
}
-unsigned AVRInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+unsigned AVRInstrInfo::removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved) const {
+ assert(!BytesRemoved && "code size not handled");
+
MachineBasicBlock::iterator I = MBB.end();
unsigned Count = 0;
@@ -429,7 +458,7 @@ unsigned AVRInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
return Count;
}
-bool AVRInstrInfo::ReverseBranchCondition(
+bool AVRInstrInfo::reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const {
assert(Cond.size() == 1 && "Invalid AVR branch condition!");
@@ -439,8 +468,8 @@ bool AVRInstrInfo::ReverseBranchCondition(
return false;
}
-unsigned AVRInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
- unsigned Opcode = MI->getOpcode();
+unsigned AVRInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
+ unsigned Opcode = MI.getOpcode();
switch (Opcode) {
// A regular instruction
@@ -454,13 +483,16 @@ unsigned AVRInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
case TargetOpcode::DBG_VALUE:
return 0;
case TargetOpcode::INLINEASM: {
- const MachineFunction *MF = MI->getParent()->getParent();
- const AVRTargetMachine &TM = static_cast<const AVRTargetMachine&>(MF->getTarget());
- const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
- return TII.getInlineAsmLength(MI->getOperand(0).getSymbolName(),
+ const MachineFunction &MF = *MI.getParent()->getParent();
+ const AVRTargetMachine &TM = static_cast<const AVRTargetMachine&>(MF.getTarget());
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ const TargetInstrInfo &TII = *STI.getInstrInfo();
+
+ return TII.getInlineAsmLength(MI.getOperand(0).getSymbolName(),
*TM.getMCAsmInfo());
}
}
}
} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.h b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.h
index fc8945d..c5105da 100644
--- a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.h
+++ b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.h
@@ -70,7 +70,7 @@ public:
const MCInstrDesc &getBrCond(AVRCC::CondCodes CC) const;
AVRCC::CondCodes getCondFromBranchOpc(unsigned Opc) const;
AVRCC::CondCodes getOppositeCondition(AVRCC::CondCodes CC) const;
- unsigned GetInstSizeInBytes(const MachineInstr *MI) const;
+ unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
@@ -94,12 +94,14 @@ public:
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify = false) const override;
- unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
+ unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
- const DebugLoc &DL) const override;
- unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
+ const DebugLoc &DL,
+ int *BytesAdded = nullptr) const override;
+ unsigned removeBranch(MachineBasicBlock &MBB,
+ int *BytesRemoved = nullptr) const override;
bool
- ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+ reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
private:
const AVRRegisterInfo RI;
diff --git a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.td b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.td
index e756836..bc66379 100644
--- a/contrib/llvm/lib/Target/AVR/AVRInstrInfo.td
+++ b/contrib/llvm/lib/Target/AVR/AVRInstrInfo.td
@@ -155,7 +155,7 @@ def memspi : Operand<iPTR>
let MIOperandInfo = (ops GPRSP, i16imm);
}
-def i8imm_com : Operand<i8>
+def imm_com8 : Operand<i8>
{
let EncoderMethod = "encodeComplement";
@@ -180,6 +180,38 @@ def call_target : Operand<iPTR>
let EncoderMethod = "encodeCallTarget";
}
+// A 16-bit address (which can lead to an R_AVR_16 relocation).
+def imm16 : Operand<i16>
+{
+ let EncoderMethod = "encodeImm<AVR::fixup_16>";
+}
+
+/// A 6-bit immediate used in the ADIW/SBIW instructions.
+def imm_arith6 : Operand<i16>
+{
+ let EncoderMethod = "encodeImm<AVR::fixup_6_adiw>";
+}
+
+/// An 8-bit immediate inside an instruction with the same format
+/// as the `LDI` instruction (the `FRdK` format).
+def imm_ldi8 : Operand<i8>
+{
+ let EncoderMethod = "encodeImm<AVR::fixup_ldi>";
+}
+
+/// A 5-bit port number used in SBIC and friends (the `FIOBIT` format).
+def imm_port5 : Operand<i8>
+{
+ let EncoderMethod = "encodeImm<AVR::fixup_port5>";
+}
+
+/// A 6-bit port number used in the `IN` instruction and friends (the
+/// `FIORdA` format.
+def imm_port6 : Operand<i8>
+{
+ let EncoderMethod = "encodeImm<AVR::fixup_port6>";
+}
+
// Addressing mode pattern reg+imm6
def addr : ComplexPattern<iPTR, 2, "SelectAddr", [], [SDNPWantRoot]>;
@@ -372,7 +404,7 @@ Defs = [SREG] in
// Adds an immediate 6-bit value K to Rd, placing the result in Rd.
def ADIWRdK : FWRdK<0b0,
(outs IWREGS:$rd),
- (ins IWREGS:$src, i16imm:$k),
+ (ins IWREGS:$src, imm_arith6:$k),
"adiw\t$rd, $k",
[(set i16:$rd, (add i16:$src, uimm6:$k)),
(implicit SREG)]>,
@@ -409,7 +441,7 @@ Defs = [SREG] in
def SUBIRdK : FRdK<0b0101,
(outs LD8:$rd),
- (ins LD8:$src, i8imm:$k),
+ (ins LD8:$src, imm_ldi8:$k),
"subi\t$rd, $k",
[(set i8:$rd, (sub i8:$src, imm:$k)),
(implicit SREG)]>;
@@ -427,7 +459,7 @@ Defs = [SREG] in
def SBIWRdK : FWRdK<0b1,
(outs IWREGS:$rd),
- (ins IWREGS:$src, i16imm:$k),
+ (ins IWREGS:$src, imm_arith6:$k),
"sbiw\t$rd, $k",
[(set i16:$rd, (sub i16:$src, uimm6:$k)),
(implicit SREG)]>,
@@ -457,7 +489,7 @@ Defs = [SREG] in
def SBCIRdK : FRdK<0b0100,
(outs LD8:$rd),
- (ins LD8:$src, i8imm:$k),
+ (ins LD8:$src, imm_ldi8:$k),
"sbci\t$rd, $k",
[(set i8:$rd, (sube i8:$src, imm:$k)),
(implicit SREG)]>;
@@ -626,7 +658,7 @@ Defs = [SREG] in
def ANDIRdK : FRdK<0b0111,
(outs LD8:$rd),
- (ins LD8:$src, i8imm:$k),
+ (ins LD8:$src, imm_ldi8:$k),
"andi\t$rd, $k",
[(set i8:$rd, (and i8:$src, imm:$k)),
(implicit SREG)]>;
@@ -644,7 +676,7 @@ Defs = [SREG] in
def ORIRdK : FRdK<0b0110,
(outs LD8:$rd),
- (ins LD8:$src, i8imm:$k),
+ (ins LD8:$src, imm_ldi8:$k),
"ori\t$rd, $k",
[(set i8:$rd, (or i8:$src, imm:$k)),
(implicit SREG)]>;
@@ -871,7 +903,7 @@ let Defs = [SREG] in
let Uses = [SREG] in
def CPIRdK : FRdK<0b0011,
(outs),
- (ins GPR8:$rd, i8imm:$k),
+ (ins GPR8:$rd, imm_ldi8:$k),
"cpi\t$rd, $k",
[(AVRcmp i8:$rd, imm:$k), (implicit SREG)]>;
}
@@ -900,13 +932,13 @@ isTerminator = 1 in
def SBICAb : FIOBIT<0b01,
(outs),
- (ins i16imm:$a, i8imm:$b),
+ (ins imm_port5:$a, i8imm:$b),
"sbic\t$a, $b",
[]>;
def SBISAb : FIOBIT<0b11,
(outs),
- (ins i16imm:$a, i8imm:$b),
+ (ins imm_port5:$a, i8imm:$b),
"sbis\t$a, $b",
[]>;
}
@@ -1065,7 +1097,7 @@ let isReMaterializable = 1 in
{
def LDIRdK : FRdK<0b1110,
(outs LD8:$rd),
- (ins i8imm:$k),
+ (ins imm_ldi8:$k),
"ldi\t$rd, $k",
[(set i8:$rd, imm:$k)]>;
@@ -1086,7 +1118,7 @@ isReMaterializable = 1 in
{
def LDSRdK : F32DM<0b0,
(outs GPR8:$rd),
- (ins i16imm:$k),
+ (ins imm16:$k),
"lds\t$rd, $k",
[(set i8:$rd, (load imm:$k))]>,
Requires<[HasSRAM]>;
@@ -1175,6 +1207,7 @@ Constraints = "$ptrreg = $base_wb,@earlyclobber $reg,@earlyclobber $base_wb" in
let canFoldAsLoad = 1,
isReMaterializable = 1 in
{
+ let Constraints = "@earlyclobber $reg" in
def LDDRdPtrQ : FSTDLDD<0,
(outs GPR8:$reg),
(ins memri:$memri),
@@ -1194,10 +1227,9 @@ isReMaterializable = 1 in
[(set i16:$dst, (load addr:$memri))]>,
Requires<[HasSRAM]>;
- //:FIXME: remove this once PR13375 gets fixed
- // Bug report: https://llvm.org/bugs/show_bug.cgi?id=13375
let mayLoad = 1,
- hasSideEffects = 0 in
+ hasSideEffects = 0,
+ Constraints = "@earlyclobber $dst" in
def LDDWRdYQ : Pseudo<(outs DREGS:$dst),
(ins memri:$memri),
"lddw\t$dst, $memri",
@@ -1205,10 +1237,42 @@ isReMaterializable = 1 in
Requires<[HasSRAM]>;
}
+class AtomicLoad<PatFrag Op, RegisterClass DRC> :
+ Pseudo<(outs DRC:$rd), (ins PTRREGS:$rr), "atomic_op",
+ [(set DRC:$rd, (Op i16:$rr))]>;
+
+class AtomicStore<PatFrag Op, RegisterClass DRC> :
+ Pseudo<(outs), (ins PTRDISPREGS:$rd, DRC:$rr), "atomic_op",
+ [(Op i16:$rd, DRC:$rr)]>;
+
+class AtomicLoadOp<PatFrag Op, RegisterClass DRC> :
+ Pseudo<(outs DRC:$rd), (ins PTRREGS:$rr, DRC:$operand),
+ "atomic_op",
+ [(set DRC:$rd, (Op i16:$rr, DRC:$operand))]>;
+
+def AtomicLoad8 : AtomicLoad<atomic_load_8, GPR8>;
+def AtomicLoad16 : AtomicLoad<atomic_load_16, DREGS>;
+
+def AtomicStore8 : AtomicStore<atomic_store_8, GPR8>;
+def AtomicStore16 : AtomicStore<atomic_store_16, DREGS>;
+
+def AtomicLoadAdd8 : AtomicLoadOp<atomic_load_add_8, GPR8>;
+def AtomicLoadAdd16 : AtomicLoadOp<atomic_load_add_16, DREGS>;
+def AtomicLoadSub8 : AtomicLoadOp<atomic_load_sub_8, GPR8>;
+def AtomicLoadSub16 : AtomicLoadOp<atomic_load_sub_16, DREGS>;
+def AtomicLoadAnd8 : AtomicLoadOp<atomic_load_and_8, GPR8>;
+def AtomicLoadAnd16 : AtomicLoadOp<atomic_load_and_16, DREGS>;
+def AtomicLoadOr8 : AtomicLoadOp<atomic_load_or_8, GPR8>;
+def AtomicLoadOr16 : AtomicLoadOp<atomic_load_or_16, DREGS>;
+def AtomicLoadXor8 : AtomicLoadOp<atomic_load_xor_8, GPR8>;
+def AtomicLoadXor16 : AtomicLoadOp<atomic_load_xor_16, DREGS>;
+def AtomicFence : Pseudo<(outs), (ins), "atomic_fence",
+ [(atomic_fence imm, imm)]>;
+
// Indirect store from register to data space.
def STSKRr : F32DM<0b1,
(outs),
- (ins i16imm:$k, GPR8:$rd),
+ (ins imm16:$k, GPR8:$rd),
"sts\t$k, $rd",
[(store i8:$rd, imm:$k)]>,
Requires<[HasSRAM]>;
@@ -1433,24 +1497,24 @@ let canFoldAsLoad = 1,
isReMaterializable = 1 in
{
def INRdA : FIORdA<(outs GPR8:$dst),
- (ins i16imm:$src),
+ (ins imm_port6:$src),
"in\t$dst, $src",
[(set i8:$dst, (load ioaddr8:$src))]>;
def INWRdA : Pseudo<(outs DREGS:$dst),
- (ins i16imm:$src),
+ (ins imm_port6:$src),
"inw\t$dst, $src",
[(set i16:$dst, (load ioaddr16:$src))]>;
}
// Write data to IO location operations.
def OUTARr : FIOARr<(outs),
- (ins i16imm:$dst, GPR8:$src),
+ (ins imm_port6:$dst, GPR8:$src),
"out\t$dst, $src",
[(store i8:$src, ioaddr8:$dst)]>;
def OUTWARr : Pseudo<(outs),
- (ins i16imm:$dst, DREGS:$src),
+ (ins imm_port6:$dst, DREGS:$src),
"outw\t$dst, $src",
[(store i16:$src, ioaddr16:$dst)]>;
@@ -1613,14 +1677,14 @@ def SWAPRd : FRd<0b1001,
// instead of in+ori+out which requires one more instr.
def SBIAb : FIOBIT<0b10,
(outs),
- (ins i16imm:$addr, i8imm:$bit),
+ (ins imm_port5:$addr, i8imm:$bit),
"sbi\t$addr, $bit",
[(store (or (i8 (load lowioaddr8:$addr)), iobitpos8:$bit),
lowioaddr8:$addr)]>;
def CBIAb : FIOBIT<0b00,
(outs),
- (ins i16imm:$addr, i8imm:$bit),
+ (ins imm_port5:$addr, i8imm:$bit),
"cbi\t$addr, $bit",
[(store (and (i8 (load lowioaddr8:$addr)), iobitposn8:$bit),
lowioaddr8:$addr)]>;
@@ -1648,16 +1712,18 @@ Defs = [SREG] in
// Alias for ORI Rd, K
def SBRRdK : FRdK<0b0110,
(outs LD8:$rd),
- (ins LD8:$src, i8imm:$k),
+ (ins LD8:$src, imm_ldi8:$k),
"sbr\t$rd, $k",
[(set i8:$rd, (or i8:$src, imm:$k)),
(implicit SREG)]>;
// CBR Rd, K
// Alias for `ANDI Rd, COM(K)` where COM(K) is the compliment of K.
+ // FIXME: This uses the 'complement' encoder. We need it to also use the
+ // imm_ldi8 encoder. This will cause no fixups to be created on this instruction.
def CBRRdK : FRdK<0b0111,
(outs LD8:$rd),
- (ins LD8:$src, i8imm_com:$k),
+ (ins LD8:$src, imm_com8:$k),
"cbr\t$rd, $k",
[]>;
}
diff --git a/contrib/llvm/lib/Target/AVR/AVRInstrumentFunctions.cpp b/contrib/llvm/lib/Target/AVR/AVRInstrumentFunctions.cpp
new file mode 100644
index 0000000..5553dc2
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRInstrumentFunctions.cpp
@@ -0,0 +1,222 @@
+//===-- AVRInstrumentFunctions.cpp - Insert instrumentation for testing ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass takes a function and inserts calls to hook functions which are
+// told the name, arguments, and results of function calls.
+//
+// The hooks can do anything with the information given. It is possible to
+// send the data through a serial connection in order to runs tests on
+// bare metal.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+
+#include <llvm/IR/Function.h>
+#include <llvm/IR/Module.h>
+
+using namespace llvm;
+
+#define AVR_INSTRUMENT_FUNCTIONS_NAME "AVR function instrumentation pass"
+
+namespace {
+
+// External symbols that we emit calls to.
+namespace symbols {
+
+#define SYMBOL_PREFIX "avr_instrumentation"
+
+ const StringRef PREFIX = SYMBOL_PREFIX;
+
+ // void (i16 argCount);
+ const StringRef BEGIN_FUNCTION_SIGNATURE = SYMBOL_PREFIX "_begin_signature";
+ // void(i16 argCount);
+ const StringRef END_FUNCTION_SIGNATURE = SYMBOL_PREFIX "_end_signature";
+
+#undef SYMBOL_PREFIX
+}
+
+class AVRInstrumentFunctions : public FunctionPass {
+public:
+ static char ID;
+
+ AVRInstrumentFunctions() : FunctionPass(ID) {
+ initializeAVRInstrumentFunctionsPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override;
+
+ StringRef getPassName() const override { return AVR_INSTRUMENT_FUNCTIONS_NAME; }
+};
+
+char AVRInstrumentFunctions::ID = 0;
+
+/// Creates a pointer to a string.
+static Value *CreateStringPtr(BasicBlock &BB, StringRef Str) {
+ LLVMContext &Ctx = BB.getContext();
+ IntegerType *I8 = Type::getInt8Ty(Ctx);
+
+ Constant *ConstantStr = ConstantDataArray::getString(Ctx, Str);
+ GlobalVariable *GlobalStr = new GlobalVariable(*BB.getParent()->getParent(),
+ ConstantStr->getType(),
+ true, /* is a constant */
+ GlobalValue::PrivateLinkage,
+ ConstantStr);
+ return GetElementPtrInst::CreateInBounds(GlobalStr,
+ {ConstantInt::get(I8, 0), ConstantInt::get(I8, 0)}, "", &BB);
+}
+
+static std::string GetTypeName(Type &Ty) {
+ if (auto *IntTy = dyn_cast<IntegerType>(&Ty)) {
+ return std::string("i") + std::to_string(IntTy->getBitWidth());
+ }
+
+ if (Ty.isFloatingPointTy()) {
+ return std::string("f") + std::to_string(Ty.getPrimitiveSizeInBits());
+ }
+
+ llvm_unreachable("unknown return type");
+}
+
+/// Builds a call to one of the signature begin/end hooks.
+static void BuildSignatureCall(StringRef SymName, BasicBlock &BB, Function &F) {
+ LLVMContext &Ctx = F.getContext();
+ IntegerType *I16 = Type::getInt16Ty(Ctx);
+
+ FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
+ {Type::getInt8PtrTy(Ctx), I16}, false);
+
+ Constant *Fn = F.getParent()->getOrInsertFunction(SymName, FnType);
+ Value *FunctionName = CreateStringPtr(BB, F.getName());
+
+ Value *Args[] = {FunctionName,
+ ConstantInt::get(I16, F.getArgumentList().size())};
+ CallInst::Create(Fn, Args, "", &BB);
+}
+
+/// Builds instructions to call into an external function to
+/// notify about a function signature beginning.
+static void BuildBeginSignature(BasicBlock &BB, Function &F) {
+ return BuildSignatureCall(symbols::BEGIN_FUNCTION_SIGNATURE, BB, F);
+}
+
+/// Builds instructions to call into an external function to
+/// notify about a function signature ending.
+static void BuildEndSignature(BasicBlock &BB, Function &F) {
+ return BuildSignatureCall(symbols::END_FUNCTION_SIGNATURE, BB, F);
+}
+
+/// Get the name of the external symbol that we need to call
+/// to notify about this argument.
+static std::string GetArgumentSymbolName(Argument &Arg) {
+ return (symbols::PREFIX + "_argument_" + GetTypeName(*Arg.getType())).str();
+}
+
+/// Builds a call to one of the argument hooks.
+static void BuildArgument(BasicBlock &BB, Argument &Arg) {
+ Function &F = *Arg.getParent();
+ LLVMContext &Ctx = F.getContext();
+
+ Type *I8 = Type::getInt8Ty(Ctx);
+
+ FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
+ {Type::getInt8PtrTy(Ctx), I8, Arg.getType()}, false);
+
+ Constant *Fn = F.getParent()->getOrInsertFunction(
+ GetArgumentSymbolName(Arg), FnType);
+ Value *ArgName = CreateStringPtr(BB, Arg.getName());
+
+ Value *Args[] = {ArgName, ConstantInt::get(I8, Arg.getArgNo()), &Arg};
+ CallInst::Create(Fn, Args, "", &BB);
+}
+
+/// Builds a call to all of the function signature hooks.
+static void BuildSignature(BasicBlock &BB, Function &F) {
+ BuildBeginSignature(BB, F);
+ for (Argument &Arg : F.args()) { BuildArgument(BB, Arg); }
+ BuildEndSignature(BB, F);
+}
+
+/// Builds the instrumentation entry block.
+static void BuildEntryBlock(Function &F) {
+ BasicBlock &EntryBlock = F.getEntryBlock();
+
+ // Create a new basic block at the start of the existing entry block.
+ BasicBlock *BB = BasicBlock::Create(F.getContext(),
+ "instrumentation_entry",
+ &F, &EntryBlock);
+
+ BuildSignature(*BB, F);
+
+ // Jump to the actual entry block.
+ BranchInst::Create(&EntryBlock, BB);
+}
+
+static std::string GetReturnSymbolName(Value &Val) {
+ return (symbols::PREFIX + "_result_" + GetTypeName(*Val.getType())).str();
+}
+
+static void BuildExitHook(Instruction &I) {
+ Function &F = *I.getParent()->getParent();
+ LLVMContext &Ctx = F.getContext();
+
+ if (auto *Ret = dyn_cast<ReturnInst>(&I)) {
+ Value *RetVal = Ret->getReturnValue();
+ assert(RetVal && "should only be instrumenting functions with return values");
+
+ FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx),
+ {RetVal->getType()}, false);
+
+ Constant *Fn = F.getParent()->getOrInsertFunction(
+ GetReturnSymbolName(*RetVal), FnType);
+
+ // Call the result hook just before the return.
+ CallInst::Create(Fn, {RetVal}, "", &I);
+ }
+}
+
+/// Runs return hooks before all returns in a function.
+static void BuildExitHooks(Function &F) {
+ for (BasicBlock &BB : F) {
+ auto BBI = BB.begin(), E = BB.end();
+ while (BBI != E) {
+ auto NBBI = std::next(BBI);
+
+ BuildExitHook(*BBI);
+
+ // Modified |= expandMI(BB, MBBI);
+ BBI = NBBI;
+ }
+ }
+}
+
+static bool ShouldInstrument(Function &F) {
+ // No point reporting results if there are none.
+ return !F.getReturnType()->isVoidTy();
+}
+
+bool AVRInstrumentFunctions::runOnFunction(Function &F) {
+ if (ShouldInstrument(F)) {
+ BuildEntryBlock(F);
+ BuildExitHooks(F);
+ }
+
+ return true;
+}
+
+} // end of anonymous namespace
+
+INITIALIZE_PASS(AVRInstrumentFunctions, "avr-instrument-functions",
+ AVR_INSTRUMENT_FUNCTIONS_NAME, false, false)
+
+namespace llvm {
+
+FunctionPass *createAVRInstrumentFunctionsPass() { return new AVRInstrumentFunctions(); }
+
+} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRMCInstLower.cpp b/contrib/llvm/lib/Target/AVR/AVRMCInstLower.cpp
new file mode 100644
index 0000000..342fe55
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRMCInstLower.cpp
@@ -0,0 +1,100 @@
+//===-- AVRMCInstLower.cpp - Convert AVR MachineInstr to an MCInst --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains code to lower AVR MachineInstrs to their corresponding
+// MCInst records.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRMCInstLower.h"
+
+#include "AVRInstrInfo.h"
+#include "MCTargetDesc/AVRMCExpr.h"
+
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace llvm {
+
+MCOperand AVRMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
+ MCSymbol *Sym) const {
+ unsigned char TF = MO.getTargetFlags();
+ const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
+
+ bool IsNegated = false;
+ if (TF & AVRII::MO_NEG) { IsNegated = true; }
+
+ if (!MO.isJTI() && MO.getOffset()) {
+ Expr = MCBinaryExpr::createAdd(
+ Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
+ }
+
+ if (TF & AVRII::MO_LO) {
+ Expr = AVRMCExpr::create(AVRMCExpr::VK_AVR_LO8, Expr, IsNegated, Ctx);
+ } else if (TF & AVRII::MO_HI) {
+ Expr = AVRMCExpr::create(AVRMCExpr::VK_AVR_HI8, Expr, IsNegated, Ctx);
+ } else if (TF != 0) {
+ llvm_unreachable("Unknown target flag on symbol operand");
+ }
+
+ return MCOperand::createExpr(Expr);
+}
+
+void AVRMCInstLower::lowerInstruction(const MachineInstr &MI, MCInst &OutMI) const {
+ OutMI.setOpcode(MI.getOpcode());
+
+ for (MachineOperand const &MO : MI.operands()) {
+ MCOperand MCOp;
+
+ switch (MO.getType()) {
+ default:
+ MI.dump();
+ llvm_unreachable("unknown operand type");
+ case MachineOperand::MO_Register:
+ // Ignore all implicit register operands.
+ if (MO.isImplicit())
+ continue;
+ MCOp = MCOperand::createReg(MO.getReg());
+ break;
+ case MachineOperand::MO_Immediate:
+ MCOp = MCOperand::createImm(MO.getImm());
+ break;
+ case MachineOperand::MO_GlobalAddress:
+ MCOp = lowerSymbolOperand(MO, Printer.getSymbol(MO.getGlobal()));
+ break;
+ case MachineOperand::MO_ExternalSymbol:
+ MCOp = lowerSymbolOperand(
+ MO, Printer.GetExternalSymbolSymbol(MO.getSymbolName()));
+ break;
+ case MachineOperand::MO_MachineBasicBlock:
+ MCOp = MCOperand::createExpr(
+ MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
+ break;
+ case MachineOperand::MO_RegisterMask:
+ continue;
+ case MachineOperand::MO_BlockAddress:
+ MCOp = lowerSymbolOperand(
+ MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress()));
+ break;
+ case MachineOperand::MO_JumpTableIndex:
+ MCOp = lowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex()));
+ break;
+ case MachineOperand::MO_ConstantPoolIndex:
+ MCOp = lowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex()));
+ break;
+ }
+
+ OutMI.addOperand(MCOp);
+ }
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRMCInstLower.h b/contrib/llvm/lib/Target/AVR/AVRMCInstLower.h
new file mode 100644
index 0000000..2e2d101
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRMCInstLower.h
@@ -0,0 +1,43 @@
+//===-- AVRMCInstLower.h - Lower MachineInstr to MCInst ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_AVR_MCINST_LOWER_H
+#define LLVM_AVR_MCINST_LOWER_H
+
+#include "llvm/Support/Compiler.h"
+
+namespace llvm {
+
+class AsmPrinter;
+class MachineInstr;
+class MachineOperand;
+class MCContext;
+class MCInst;
+class MCOperand;
+class MCSymbol;
+
+/// Lowers `MachineInstr` objects into `MCInst` objects.
+class AVRMCInstLower {
+public:
+ AVRMCInstLower(MCContext &Ctx, AsmPrinter &Printer)
+ : Ctx(Ctx), Printer(Printer) {}
+
+ /// Lowers a `MachineInstr` into a `MCInst`.
+ void lowerInstruction(const MachineInstr &MI, MCInst &OutMI) const;
+ MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const;
+
+private:
+ MCContext &Ctx;
+ AsmPrinter &Printer;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_AVR_MCINST_LOWER_H
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.cpp b/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
index 5786f74..48798bd 100644
--- a/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
+++ b/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
@@ -129,13 +129,13 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
const MachineFunction &MF = *MBB.getParent();
const AVRTargetMachine &TM = (const AVRTargetMachine &)MF.getTarget();
const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
- const MachineFrameInfo *MFI = MF.getFrameInfo();
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetFrameLowering *TFI = TM.getSubtargetImpl()->getFrameLowering();
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
- int Offset = MFI->getObjectOffset(FrameIndex);
+ int Offset = MFI.getObjectOffset(FrameIndex);
// Add one to the offset because SP points to an empty slot.
- Offset += MFI->getStackSize() - TFI->getOffsetOfLocalArea() + 1;
+ Offset += MFI.getStackSize() - TFI->getOffsetOfLocalArea() + 1;
// Fold incoming offset.
Offset += MI.getOperand(FIOperandNum + 1).getImm();
@@ -172,7 +172,7 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
Opcode = AVR::ADIWRdK;
break;
}
- // Fallthrough
+ LLVM_FALLTHROUGH;
}
default: {
// This opcode will get expanded into a pair of subi/sbci.
@@ -193,7 +193,7 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
// If the offset is too big we have to adjust and restore the frame pointer
// to materialize a valid load/store with displacement.
//:TODO: consider using only one adiw/sbiw chain for more than one frame index
- if (Offset >= 63) {
+ if (Offset > 63) {
unsigned AddOpc = AVR::ADIWRdK, SubOpc = AVR::SBIWRdK;
int AddOffset = Offset - 63 + 1;
@@ -253,4 +253,14 @@ AVRRegisterInfo::getPointerRegClass(const MachineFunction &MF,
return &AVR::PTRDISPREGSRegClass;
}
+void AVRRegisterInfo::splitReg(unsigned Reg,
+ unsigned &LoReg,
+ unsigned &HiReg) const {
+ assert(AVR::DREGSRegClass.contains(Reg) && "can only split 16-bit registers");
+
+ LoReg = getSubReg(Reg, AVR::sub_lo);
+ HiReg = getSubReg(Reg, AVR::sub_hi);
+}
+
} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.h b/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.h
index 59c0849..b97e32e 100644
--- a/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.h
+++ b/contrib/llvm/lib/Target/AVR/AVRRegisterInfo.h
@@ -42,13 +42,15 @@ public:
unsigned FIOperandNum,
RegScavenger *RS = NULL) const override;
- /// Debug information queries.
unsigned getFrameRegister(const MachineFunction &MF) const override;
- /// Returns a TargetRegisterClass used for pointer values.
const TargetRegisterClass *
getPointerRegClass(const MachineFunction &MF,
unsigned Kind = 0) const override;
+
+ /// Splits a 16-bit `DREGS` register into the lo/hi register pair.
+ /// \param Reg A 16-bit register to split.
+ void splitReg(unsigned Reg, unsigned &LoReg, unsigned &HiReg) const;
};
} // end namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp b/contrib/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp
new file mode 100644
index 0000000..26dbcf7
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp
@@ -0,0 +1,149 @@
+//===-- AVRRelaxMemOperations.cpp - Relax out of range loads/stores -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a pass which relaxes out of range memory operations into
+// equivalent operations which handle bigger addresses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRInstrInfo.h"
+#include "AVRTargetMachine.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+
+using namespace llvm;
+
+#define AVR_RELAX_MEM_OPS_NAME "AVR memory operation relaxation pass"
+
+namespace {
+
+class AVRRelaxMem : public MachineFunctionPass {
+public:
+ static char ID;
+
+ AVRRelaxMem() : MachineFunctionPass(ID) {
+ initializeAVRRelaxMemPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ StringRef getPassName() const override { return AVR_RELAX_MEM_OPS_NAME; }
+
+private:
+ typedef MachineBasicBlock Block;
+ typedef Block::iterator BlockIt;
+
+ const TargetInstrInfo *TII;
+
+ template <unsigned OP> bool relax(Block &MBB, BlockIt MBBI);
+
+ bool runOnBasicBlock(Block &MBB);
+ bool runOnInstruction(Block &MBB, BlockIt MBBI);
+
+ MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned Opcode) {
+ return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode));
+ }
+};
+
+char AVRRelaxMem::ID = 0;
+
+bool AVRRelaxMem::runOnMachineFunction(MachineFunction &MF) {
+ bool Modified = false;
+
+ const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
+ TII = STI.getInstrInfo();
+
+ for (Block &MBB : MF) {
+ bool BlockModified = runOnBasicBlock(MBB);
+ Modified |= BlockModified;
+ }
+
+ return Modified;
+}
+
+bool AVRRelaxMem::runOnBasicBlock(Block &MBB) {
+ bool Modified = false;
+
+ BlockIt MBBI = MBB.begin(), E = MBB.end();
+ while (MBBI != E) {
+ BlockIt NMBBI = std::next(MBBI);
+ Modified |= runOnInstruction(MBB, MBBI);
+ MBBI = NMBBI;
+ }
+
+ return Modified;
+}
+
+template <>
+bool AVRRelaxMem::relax<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+
+ MachineOperand &Ptr = MI.getOperand(0);
+ MachineOperand &Src = MI.getOperand(2);
+ int64_t Imm = MI.getOperand(1).getImm();
+
+ // We can definitely optimise this better.
+ if (Imm > 63) {
+ // Push the previous state of the pointer register.
+ // This instruction must preserve the value.
+ buildMI(MBB, MBBI, AVR::PUSHWRr)
+ .addReg(Ptr.getReg());
+
+ // Add the immediate to the pointer register.
+ buildMI(MBB, MBBI, AVR::SBCIWRdK)
+ .addReg(Ptr.getReg(), RegState::Define)
+ .addReg(Ptr.getReg())
+ .addImm(-Imm);
+
+ // Store the value in the source register to the address
+ // pointed to by the pointer register.
+ buildMI(MBB, MBBI, AVR::STWPtrRr)
+ .addReg(Ptr.getReg())
+ .addReg(Src.getReg(), getKillRegState(Src.isKill()));
+
+ // Pop the original state of the pointer register.
+ buildMI(MBB, MBBI, AVR::POPWRd)
+ .addReg(Ptr.getReg(), getKillRegState(Ptr.isKill()));
+
+ MI.removeFromParent();
+ }
+
+ return false;
+}
+
+bool AVRRelaxMem::runOnInstruction(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ int Opcode = MBBI->getOpcode();
+
+#define RELAX(Op) \
+ case Op: \
+ return relax<Op>(MBB, MI)
+
+ switch (Opcode) {
+ RELAX(AVR::STDWPtrQRr);
+ }
+#undef RELAX
+ return false;
+}
+
+} // end of anonymous namespace
+
+INITIALIZE_PASS(AVRRelaxMem, "avr-relax-mem",
+ AVR_RELAX_MEM_OPS_NAME, false, false)
+
+namespace llvm {
+
+FunctionPass *createAVRRelaxMemPass() { return new AVRRelaxMem(); }
+
+} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRTargetMachine.cpp b/contrib/llvm/lib/Target/AVR/AVRTargetMachine.cpp
index 508723e..fb32629 100644
--- a/contrib/llvm/lib/Target/AVR/AVRTargetMachine.cpp
+++ b/contrib/llvm/lib/Target/AVR/AVRTargetMachine.cpp
@@ -25,6 +25,8 @@
namespace llvm {
+static const char *AVRDataLayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8";
+
/// Processes a CPU name.
static StringRef getCPU(StringRef CPU) {
if (CPU.empty() || CPU == "generic") {
@@ -44,7 +46,7 @@ AVRTargetMachine::AVRTargetMachine(const Target &T, const Triple &TT,
Optional<Reloc::Model> RM, CodeModel::Model CM,
CodeGenOpt::Level OL)
: LLVMTargetMachine(
- T, "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-i64:8:8-f32:8:8-f64:8:8-n8", TT,
+ T, AVRDataLayout, TT,
getCPU(CPU), FS, Options, getEffectiveRelocModel(RM), CM, OL),
SubTarget(TT, getCPU(CPU), FS, *this) {
this->TLOF = make_unique<AVRTargetObjectFile>();
@@ -65,7 +67,6 @@ public:
bool addInstSelector() override;
void addPreSched2() override;
void addPreRegAlloc() override;
- void addPreEmitPass() override;
};
} // namespace
@@ -75,7 +76,12 @@ TargetPassConfig *AVRTargetMachine::createPassConfig(PassManagerBase &PM) {
extern "C" void LLVMInitializeAVRTarget() {
// Register the target.
- RegisterTargetMachine<AVRTargetMachine> X(TheAVRTarget);
+ RegisterTargetMachine<AVRTargetMachine> X(getTheAVRTarget());
+
+ auto &PR = *PassRegistry::getPassRegistry();
+ initializeAVRExpandPseudoPass(PR);
+ initializeAVRInstrumentFunctionsPass(PR);
+ initializeAVRRelaxMemPass(PR);
}
const AVRSubtarget *AVRTargetMachine::getSubtargetImpl() const {
@@ -91,15 +97,22 @@ const AVRSubtarget *AVRTargetMachine::getSubtargetImpl(const Function &) const {
//===----------------------------------------------------------------------===//
bool AVRPassConfig::addInstSelector() {
+ // Install an instruction selector.
+ addPass(createAVRISelDag(getAVRTargetMachine(), getOptLevel()));
+ // Create the frame analyzer pass used by the PEI pass.
+ addPass(createAVRFrameAnalyzerPass());
+
return false;
}
void AVRPassConfig::addPreRegAlloc() {
+ // Create the dynalloc SP save/restore pass to handle variable sized allocas.
+ addPass(createAVRDynAllocaSRPass());
}
-void AVRPassConfig::addPreSched2() { }
-
-void AVRPassConfig::addPreEmitPass() {
+void AVRPassConfig::addPreSched2() {
+ addPass(createAVRRelaxMemPass());
+ addPass(createAVRExpandPseudoPass());
}
} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp b/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp
index 85f03e8..af14d92 100644
--- a/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp
+++ b/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp
@@ -26,15 +26,16 @@ void AVRTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM) {
}
MCSection *
-AVRTargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV,
- SectionKind Kind, Mangler &Mang,
+AVRTargetObjectFile::SelectSectionForGlobal(const GlobalObject *GO,
+ SectionKind Kind,
const TargetMachine &TM) const {
// Global values in flash memory are placed in the progmem.data section
// unless they already have a user assigned section.
- if (AVR::isProgramMemoryAddress(GV) && !GV->hasSection())
+ if (AVR::isProgramMemoryAddress(GO) && !GO->hasSection())
return ProgmemDataSection;
// Otherwise, we work the same way as ELF.
- return Base::SelectSectionForGlobal(GV, Kind, Mang, TM);
+ return Base::SelectSectionForGlobal(GO, Kind, TM);
}
} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.h b/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.h
index 5876125..ba91036 100644
--- a/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.h
+++ b/contrib/llvm/lib/Target/AVR/AVRTargetObjectFile.h
@@ -21,8 +21,7 @@ class AVRTargetObjectFile : public TargetLoweringObjectFileELF {
public:
void Initialize(MCContext &ctx, const TargetMachine &TM) override;
- MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
- Mangler &Mang,
+ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
const TargetMachine &TM) const override;
private:
diff --git a/contrib/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp b/contrib/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp
new file mode 100644
index 0000000..5b0398c
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp
@@ -0,0 +1,631 @@
+//===---- AVRAsmParser.cpp - Parse AVR assembly to MCInst instructions ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRRegisterInfo.h"
+#include "MCTargetDesc/AVRMCExpr.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/TargetRegistry.h"
+
+#include <sstream>
+
+#define DEBUG_TYPE "avr-asm-parser"
+
+namespace llvm {
+
+/// Parses AVR assembly from a stream.
+class AVRAsmParser : public MCTargetAsmParser {
+ const MCSubtargetInfo &STI;
+ MCAsmParser &Parser;
+ const MCRegisterInfo *MRI;
+
+#define GET_ASSEMBLER_HEADER
+#include "AVRGenAsmMatcher.inc"
+
+ bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+ OperandVector &Operands, MCStreamer &Out,
+ uint64_t &ErrorInfo,
+ bool MatchingInlineAsm) override;
+
+ bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
+
+ bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+ SMLoc NameLoc, OperandVector &Operands) override;
+
+ bool ParseDirective(AsmToken directiveID) override;
+
+ OperandMatchResultTy parseMemriOperand(OperandVector &Operands);
+
+ bool parseOperand(OperandVector &Operands);
+ int parseRegisterName(unsigned (*matchFn)(StringRef));
+ int parseRegisterName();
+ int parseRegister();
+ bool tryParseRegisterOperand(OperandVector &Operands);
+ bool tryParseExpression(OperandVector &Operands);
+ bool tryParseRelocExpression(OperandVector &Operands);
+ void eatComma();
+
+ unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
+ unsigned Kind) override;
+
+ unsigned toDREG(unsigned Reg, unsigned From = AVR::sub_lo) {
+ MCRegisterClass const *Class = &AVRMCRegisterClasses[AVR::DREGSRegClassID];
+ return MRI->getMatchingSuperReg(Reg, From, Class);
+ }
+
+ bool emit(MCInst &Instruction, SMLoc const &Loc, MCStreamer &Out) const;
+ bool invalidOperand(SMLoc const &Loc, OperandVector const &Operands,
+ uint64_t const &ErrorInfo);
+ bool missingFeature(SMLoc const &Loc, uint64_t const &ErrorInfo);
+
+public:
+ AVRAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
+ const MCInstrInfo &MII, const MCTargetOptions &Options)
+ : MCTargetAsmParser(Options, STI), STI(STI), Parser(Parser) {
+ MCAsmParserExtension::Initialize(Parser);
+ MRI = getContext().getRegisterInfo();
+
+ setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
+ }
+
+ MCAsmParser &getParser() const { return Parser; }
+ MCAsmLexer &getLexer() const { return Parser.getLexer(); }
+};
+
+/// An parsed AVR assembly operand.
+class AVROperand : public MCParsedAsmOperand {
+ typedef MCParsedAsmOperand Base;
+ enum KindTy { k_Immediate, k_Register, k_Token, k_Memri } Kind;
+
+public:
+ AVROperand(StringRef Tok, SMLoc const &S)
+ : Base(), Kind(k_Token), Tok(Tok), Start(S), End(S) {}
+ AVROperand(unsigned Reg, SMLoc const &S, SMLoc const &E)
+ : Base(), Kind(k_Register), RegImm({Reg, nullptr}), Start(S), End(E) {}
+ AVROperand(MCExpr const *Imm, SMLoc const &S, SMLoc const &E)
+ : Base(), Kind(k_Immediate), RegImm({0, Imm}), Start(S), End(E) {}
+ AVROperand(unsigned Reg, MCExpr const *Imm, SMLoc const &S, SMLoc const &E)
+ : Base(), Kind(k_Memri), RegImm({Reg, Imm}), Start(S), End(E) {}
+
+ struct RegisterImmediate {
+ unsigned Reg;
+ MCExpr const *Imm;
+ };
+ union {
+ StringRef Tok;
+ RegisterImmediate RegImm;
+ };
+
+ SMLoc Start, End;
+
+public:
+ void addRegOperands(MCInst &Inst, unsigned N) const {
+ assert(Kind == k_Register && "Unexpected operand kind");
+ assert(N == 1 && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::createReg(getReg()));
+ }
+
+ void addExpr(MCInst &Inst, const MCExpr *Expr) const {
+ // Add as immediate when possible
+ if (!Expr)
+ Inst.addOperand(MCOperand::createImm(0));
+ else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
+ Inst.addOperand(MCOperand::createImm(CE->getValue()));
+ else
+ Inst.addOperand(MCOperand::createExpr(Expr));
+ }
+
+ void addImmOperands(MCInst &Inst, unsigned N) const {
+ assert(Kind == k_Immediate && "Unexpected operand kind");
+ assert(N == 1 && "Invalid number of operands!");
+
+ const MCExpr *Expr = getImm();
+ addExpr(Inst, Expr);
+ }
+
+ /// Adds the contained reg+imm operand to an instruction.
+ void addMemriOperands(MCInst &Inst, unsigned N) const {
+ assert(Kind == k_Memri && "Unexpected operand kind");
+ assert(N == 2 && "Invalid number of operands");
+
+ Inst.addOperand(MCOperand::createReg(getReg()));
+ addExpr(Inst, getImm());
+ }
+
+ bool isReg() const { return Kind == k_Register; }
+ bool isImm() const { return Kind == k_Immediate; }
+ bool isToken() const { return Kind == k_Token; }
+ bool isMem() const { return Kind == k_Memri; }
+ bool isMemri() const { return Kind == k_Memri; }
+
+ StringRef getToken() const {
+ assert(Kind == k_Token && "Invalid access!");
+ return Tok;
+ }
+
+ unsigned getReg() const {
+ assert((Kind == k_Register || Kind == k_Memri) && "Invalid access!");
+
+ return RegImm.Reg;
+ }
+
+ const MCExpr *getImm() const {
+ assert((Kind == k_Immediate || Kind == k_Memri) && "Invalid access!");
+ return RegImm.Imm;
+ }
+
+ static std::unique_ptr<AVROperand> CreateToken(StringRef Str, SMLoc S) {
+ return make_unique<AVROperand>(Str, S);
+ }
+
+ static std::unique_ptr<AVROperand> CreateReg(unsigned RegNum, SMLoc S,
+ SMLoc E) {
+ return make_unique<AVROperand>(RegNum, S, E);
+ }
+
+ static std::unique_ptr<AVROperand> CreateImm(const MCExpr *Val, SMLoc S,
+ SMLoc E) {
+ return make_unique<AVROperand>(Val, S, E);
+ }
+
+ static std::unique_ptr<AVROperand>
+ CreateMemri(unsigned RegNum, const MCExpr *Val, SMLoc S, SMLoc E) {
+ return make_unique<AVROperand>(RegNum, Val, S, E);
+ }
+
+ void makeToken(StringRef Token) {
+ Kind = k_Token;
+ Tok = Token;
+ }
+
+ void makeReg(unsigned RegNo) {
+ Kind = k_Register;
+ RegImm = {RegNo, nullptr};
+ }
+
+ void makeImm(MCExpr const *Ex) {
+ Kind = k_Immediate;
+ RegImm = {0, Ex};
+ }
+
+ void makeMemri(unsigned RegNo, MCExpr const *Imm) {
+ Kind = k_Memri;
+ RegImm = {RegNo, Imm};
+ }
+
+ SMLoc getStartLoc() const { return Start; }
+ SMLoc getEndLoc() const { return End; }
+
+ virtual void print(raw_ostream &O) const {
+ switch (Kind) {
+ case k_Token:
+ O << "Token: \"" << getToken() << "\"";
+ break;
+ case k_Register:
+ O << "Register: " << getReg();
+ break;
+ case k_Immediate:
+ O << "Immediate: \"" << *getImm() << "\"";
+ break;
+ case k_Memri: {
+ // only manually print the size for non-negative values,
+ // as the sign is inserted automatically.
+ O << "Memri: \"" << getReg() << '+' << *getImm() << "\"";
+ break;
+ }
+ }
+ O << "\n";
+ }
+};
+
+// Auto-generated Match Functions
+
+/// Maps from the set of all register names to a register number.
+/// \note Generated by TableGen.
+static unsigned MatchRegisterName(StringRef Name);
+
+/// Maps from the set of all alternative registernames to a register number.
+/// \note Generated by TableGen.
+static unsigned MatchRegisterAltName(StringRef Name);
+
+bool AVRAsmParser::invalidOperand(SMLoc const &Loc,
+ OperandVector const &Operands,
+ uint64_t const &ErrorInfo) {
+ SMLoc ErrorLoc = Loc;
+ char const *Diag = 0;
+
+ if (ErrorInfo != ~0U) {
+ if (ErrorInfo >= Operands.size()) {
+ Diag = "too few operands for instruction.";
+ } else {
+ AVROperand const &Op = (AVROperand const &)*Operands[ErrorInfo];
+
+ // TODO: See if we can do a better error than just "invalid ...".
+ if (Op.getStartLoc() != SMLoc()) {
+ ErrorLoc = Op.getStartLoc();
+ }
+ }
+ }
+
+ if (!Diag) {
+ Diag = "invalid operand for instruction";
+ }
+
+ return Error(ErrorLoc, Diag);
+}
+
+bool AVRAsmParser::missingFeature(llvm::SMLoc const &Loc,
+ uint64_t const &ErrorInfo) {
+ return Error(Loc, "instruction requires a CPU feature not currently enabled");
+}
+
+bool AVRAsmParser::emit(MCInst &Inst, SMLoc const &Loc, MCStreamer &Out) const {
+ Inst.setLoc(Loc);
+ Out.EmitInstruction(Inst, STI);
+
+ return false;
+}
+
+bool AVRAsmParser::MatchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,
+ OperandVector &Operands,
+ MCStreamer &Out, uint64_t &ErrorInfo,
+ bool MatchingInlineAsm) {
+ MCInst Inst;
+ unsigned MatchResult =
+ MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
+
+ switch (MatchResult) {
+ case Match_Success: return emit(Inst, Loc, Out);
+ case Match_MissingFeature: return missingFeature(Loc, ErrorInfo);
+ case Match_InvalidOperand: return invalidOperand(Loc, Operands, ErrorInfo);
+ case Match_MnemonicFail: return Error(Loc, "invalid instruction");
+ default: return true;
+ }
+}
+
+/// Parses a register name using a given matching function.
+/// Checks for lowercase or uppercase if necessary.
+int AVRAsmParser::parseRegisterName(unsigned (*matchFn)(StringRef)) {
+ StringRef Name = Parser.getTok().getString();
+
+ int RegNum = matchFn(Name);
+
+ // GCC supports case insensitive register names. Some of the AVR registers
+ // are all lower case, some are all upper case but non are mixed. We prefer
+ // to use the original names in the register definitions. That is why we
+ // have to test both upper and lower case here.
+ if (RegNum == AVR::NoRegister) {
+ RegNum = matchFn(Name.lower());
+ }
+ if (RegNum == AVR::NoRegister) {
+ RegNum = matchFn(Name.upper());
+ }
+
+ return RegNum;
+}
+
+int AVRAsmParser::parseRegisterName() {
+ int RegNum = parseRegisterName(&MatchRegisterName);
+
+ if (RegNum == AVR::NoRegister)
+ RegNum = parseRegisterName(&MatchRegisterAltName);
+
+ return RegNum;
+}
+
+int AVRAsmParser::parseRegister() {
+ int RegNum = AVR::NoRegister;
+
+ if (Parser.getTok().is(AsmToken::Identifier)) {
+ // Check for register pair syntax
+ if (Parser.getLexer().peekTok().is(AsmToken::Colon)) {
+ Parser.Lex();
+ Parser.Lex(); // Eat high (odd) register and colon
+
+ if (Parser.getTok().is(AsmToken::Identifier)) {
+ // Convert lower (even) register to DREG
+ RegNum = toDREG(parseRegisterName());
+ }
+ } else {
+ RegNum = parseRegisterName();
+ }
+ }
+ return RegNum;
+}
+
+bool AVRAsmParser::tryParseRegisterOperand(OperandVector &Operands) {
+ int RegNo = parseRegister();
+
+ if (RegNo == AVR::NoRegister)
+ return true;
+
+ AsmToken const &T = Parser.getTok();
+ Operands.push_back(AVROperand::CreateReg(RegNo, T.getLoc(), T.getEndLoc()));
+ Parser.Lex(); // Eat register token.
+
+ return false;
+}
+
+bool AVRAsmParser::tryParseExpression(OperandVector &Operands) {
+ SMLoc S = Parser.getTok().getLoc();
+
+ if (!tryParseRelocExpression(Operands))
+ return false;
+
+ if ((Parser.getTok().getKind() == AsmToken::Plus ||
+ Parser.getTok().getKind() == AsmToken::Minus) &&
+ Parser.getLexer().peekTok().getKind() == AsmToken::Identifier) {
+ // Don't handle this case - it should be split into two
+ // separate tokens.
+ return true;
+ }
+
+ // Parse (potentially inner) expression
+ MCExpr const *Expression;
+ if (getParser().parseExpression(Expression))
+ return true;
+
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ Operands.push_back(AVROperand::CreateImm(Expression, S, E));
+ return false;
+}
+
+bool AVRAsmParser::tryParseRelocExpression(OperandVector &Operands) {
+ bool isNegated = false;
+ AVRMCExpr::VariantKind ModifierKind = AVRMCExpr::VK_AVR_None;
+
+ SMLoc S = Parser.getTok().getLoc();
+
+ // Check for sign
+ AsmToken tokens[2];
+ size_t ReadCount = Parser.getLexer().peekTokens(tokens);
+
+ if (ReadCount == 2) {
+ if (tokens[0].getKind() == AsmToken::Identifier &&
+ tokens[1].getKind() == AsmToken::LParen) {
+
+ AsmToken::TokenKind CurTok = Parser.getLexer().getKind();
+ if (CurTok == AsmToken::Minus) {
+ isNegated = true;
+ } else {
+ assert(CurTok == AsmToken::Plus);
+ isNegated = false;
+ }
+
+ // Eat the sign
+ Parser.Lex();
+ }
+ }
+
+ // Check if we have a target specific modifier (lo8, hi8, &c)
+ if (Parser.getTok().getKind() != AsmToken::Identifier ||
+ Parser.getLexer().peekTok().getKind() != AsmToken::LParen) {
+ // Not a reloc expr
+ return true;
+ }
+ StringRef ModifierName = Parser.getTok().getString();
+ ModifierKind = AVRMCExpr::getKindByName(ModifierName.str().c_str());
+
+ if (ModifierKind != AVRMCExpr::VK_AVR_None) {
+ Parser.Lex();
+ Parser.Lex(); // Eat modifier name and parenthesis
+ } else {
+ return Error(Parser.getTok().getLoc(), "unknown modifier");
+ }
+
+ MCExpr const *InnerExpression;
+ if (getParser().parseExpression(InnerExpression))
+ return true;
+
+ // If we have a modifier wrap the inner expression
+ assert(Parser.getTok().getKind() == AsmToken::RParen);
+ Parser.Lex(); // Eat closing parenthesis
+
+ MCExpr const *Expression = AVRMCExpr::create(ModifierKind, InnerExpression,
+ isNegated, getContext());
+
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ Operands.push_back(AVROperand::CreateImm(Expression, S, E));
+
+ return false;
+}
+
+bool AVRAsmParser::parseOperand(OperandVector &Operands) {
+ DEBUG(dbgs() << "parseOperand\n");
+
+ switch (getLexer().getKind()) {
+ default:
+ return Error(Parser.getTok().getLoc(), "unexpected token in operand");
+
+ case AsmToken::Identifier:
+ // Try to parse a register, if it fails,
+ // fall through to the next case.
+ if (!tryParseRegisterOperand(Operands)) {
+ return false;
+ }
+ case AsmToken::LParen:
+ case AsmToken::Integer:
+ case AsmToken::Dot:
+ return tryParseExpression(Operands);
+ case AsmToken::Plus:
+ case AsmToken::Minus: {
+ // If the sign preceeds a number, parse the number,
+ // otherwise treat the sign a an independent token.
+ switch (getLexer().peekTok().getKind()) {
+ case AsmToken::Integer:
+ case AsmToken::BigNum:
+ case AsmToken::Identifier:
+ case AsmToken::Real:
+ if (!tryParseExpression(Operands))
+ return false;
+ default:
+ break;
+ }
+ // Treat the token as an independent token.
+ Operands.push_back(AVROperand::CreateToken(Parser.getTok().getString(),
+ Parser.getTok().getLoc()));
+ Parser.Lex(); // Eat the token.
+ return false;
+ }
+ }
+
+ // Could not parse operand
+ return true;
+}
+
+OperandMatchResultTy
+AVRAsmParser::parseMemriOperand(OperandVector &Operands) {
+ DEBUG(dbgs() << "parseMemriOperand()\n");
+
+ SMLoc E, S;
+ MCExpr const *Expression;
+ int RegNo;
+
+ // Parse register.
+ {
+ RegNo = parseRegister();
+
+ if (RegNo == AVR::NoRegister)
+ return MatchOperand_ParseFail;
+
+ S = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ Parser.Lex(); // Eat register token.
+ }
+
+ // Parse immediate;
+ {
+ if (getParser().parseExpression(Expression))
+ return MatchOperand_ParseFail;
+
+ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ }
+
+ Operands.push_back(AVROperand::CreateMemri(RegNo, Expression, S, E));
+
+ return MatchOperand_Success;
+}
+
+bool AVRAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
+ SMLoc &EndLoc) {
+ StartLoc = Parser.getTok().getLoc();
+ RegNo = parseRegister();
+ EndLoc = Parser.getTok().getLoc();
+
+ return (RegNo == AVR::NoRegister);
+}
+
+void AVRAsmParser::eatComma() {
+ if (getLexer().is(AsmToken::Comma)) {
+ Parser.Lex();
+ } else {
+ // GCC allows commas to be omitted.
+ }
+}
+
+bool AVRAsmParser::ParseInstruction(ParseInstructionInfo &Info,
+ StringRef Mnemonic, SMLoc NameLoc,
+ OperandVector &Operands) {
+ Operands.push_back(AVROperand::CreateToken(Mnemonic, NameLoc));
+
+ bool first = true;
+ while (getLexer().isNot(AsmToken::EndOfStatement)) {
+ if (!first) eatComma();
+
+ first = false;
+
+ auto MatchResult = MatchOperandParserImpl(Operands, Mnemonic);
+
+ if (MatchResult == MatchOperand_Success) {
+ continue;
+ }
+
+ if (MatchResult == MatchOperand_ParseFail) {
+ SMLoc Loc = getLexer().getLoc();
+ Parser.eatToEndOfStatement();
+
+ return Error(Loc, "failed to parse register and immediate pair");
+ }
+
+ if (parseOperand(Operands)) {
+ SMLoc Loc = getLexer().getLoc();
+ Parser.eatToEndOfStatement();
+ return Error(Loc, "unexpected token in argument list");
+ }
+ }
+ Parser.Lex(); // Consume the EndOfStatement
+ return false;
+}
+
+bool AVRAsmParser::ParseDirective(llvm::AsmToken DirectiveID) { return true; }
+
+extern "C" void LLVMInitializeAVRAsmParser() {
+ RegisterMCAsmParser<AVRAsmParser> X(getTheAVRTarget());
+}
+
+#define GET_REGISTER_MATCHER
+#define GET_MATCHER_IMPLEMENTATION
+#include "AVRGenAsmMatcher.inc"
+
+// Uses enums defined in AVRGenAsmMatcher.inc
+unsigned AVRAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
+ unsigned ExpectedKind) {
+ AVROperand &Op = static_cast<AVROperand &>(AsmOp);
+ MatchClassKind Expected = static_cast<MatchClassKind>(ExpectedKind);
+
+ // If need be, GCC converts bare numbers to register names
+ // It's ugly, but GCC supports it.
+ if (Op.isImm()) {
+ if (MCConstantExpr const *Const = dyn_cast<MCConstantExpr>(Op.getImm())) {
+ int64_t RegNum = Const->getValue();
+ std::ostringstream RegName;
+ RegName << "r" << RegNum;
+ RegNum = MatchRegisterName(RegName.str().c_str());
+ if (RegNum != AVR::NoRegister) {
+ Op.makeReg(RegNum);
+ if (validateOperandClass(Op, Expected) == Match_Success) {
+ return Match_Success;
+ }
+ }
+ // Let the other quirks try their magic.
+ }
+ }
+
+ if (Op.isReg()) {
+ // If the instruction uses a register pair but we got a single, lower
+ // register we perform a "class cast".
+ if (isSubclass(Expected, MCK_DREGS)) {
+ unsigned correspondingDREG = toDREG(Op.getReg());
+
+ if (correspondingDREG != AVR::NoRegister) {
+ Op.makeReg(correspondingDREG);
+ return validateOperandClass(Op, Expected);
+ }
+ }
+ }
+ return Match_InvalidOperand;
+}
+
+} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp b/contrib/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp
new file mode 100644
index 0000000..d2a21fb
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp
@@ -0,0 +1,156 @@
+//===- AVRDisassembler.cpp - Disassembler for AVR ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the AVR Disassembler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "AVRRegisterInfo.h"
+#include "AVRSubtarget.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCFixedLenDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "avr-disassembler"
+
+typedef MCDisassembler::DecodeStatus DecodeStatus;
+
+namespace {
+
+/// A disassembler class for AVR.
+class AVRDisassembler : public MCDisassembler {
+public:
+ AVRDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
+ : MCDisassembler(STI, Ctx) {}
+ virtual ~AVRDisassembler() {}
+
+ DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const override;
+};
+}
+
+static MCDisassembler *createAVRDisassembler(const Target &T,
+ const MCSubtargetInfo &STI,
+ MCContext &Ctx) {
+ return new AVRDisassembler(STI, Ctx);
+}
+
+
+extern "C" void LLVMInitializeAVRDisassembler() {
+ // Register the disassembler.
+ TargetRegistry::RegisterMCDisassembler(getTheAVRTarget(),
+ createAVRDisassembler);
+}
+
+static DecodeStatus DecodeGPR8RegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeLD8RegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodePTRREGSRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ return MCDisassembler::Success;
+}
+
+#include "AVRGenDisassemblerTables.inc"
+
+static DecodeStatus readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address,
+ uint64_t &Size, uint32_t &Insn) {
+ if (Bytes.size() < 2) {
+ Size = 0;
+ return MCDisassembler::Fail;
+ }
+
+ Size = 2;
+ Insn = (Bytes[0] << 0) | (Bytes[1] << 8);
+
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
+ uint64_t &Size, uint32_t &Insn) {
+
+ if (Bytes.size() < 4) {
+ Size = 0;
+ return MCDisassembler::Fail;
+ }
+
+ Size = 4;
+ Insn = (Bytes[0] << 0) | (Bytes[1] << 8) | (Bytes[2] << 16) | (Bytes[3] << 24);
+
+ return MCDisassembler::Success;
+}
+
+static const uint8_t *getDecoderTable(uint64_t Size) {
+
+ switch (Size) {
+ case 2: return DecoderTable16;
+ case 4: return DecoderTable32;
+ default: llvm_unreachable("instructions must be 16 or 32-bits");
+ }
+}
+
+DecodeStatus AVRDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const {
+ uint32_t Insn;
+
+ DecodeStatus Result;
+
+ // Try decode a 16-bit instruction.
+ {
+ Result = readInstruction16(Bytes, Address, Size, Insn);
+
+ if (Result == MCDisassembler::Fail) return MCDisassembler::Fail;
+
+ // Try to auto-decode a 16-bit instruction.
+ Result = decodeInstruction(getDecoderTable(Size), Instr,
+ Insn, Address, this, STI);
+
+ if (Result != MCDisassembler::Fail)
+ return Result;
+ }
+
+ // Try decode a 32-bit instruction.
+ {
+ Result = readInstruction32(Bytes, Address, Size, Insn);
+
+ if (Result == MCDisassembler::Fail) return MCDisassembler::Fail;
+
+ Result = decodeInstruction(getDecoderTable(Size), Instr, Insn,
+ Address, this, STI);
+
+ if (Result != MCDisassembler::Fail) {
+ return Result;
+ }
+
+ return MCDisassembler::Fail;
+ }
+}
+
+typedef DecodeStatus (*DecodeFunc)(MCInst &MI, unsigned insn, uint64_t Address,
+ const void *Decoder);
+
diff --git a/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.cpp b/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.cpp
new file mode 100644
index 0000000..316b783
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.cpp
@@ -0,0 +1,171 @@
+//===-- AVRInstPrinter.cpp - Convert AVR MCInst to assembly syntax --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class prints an AVR MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRInstPrinter.h"
+
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormattedStream.h"
+
+#include <cstring>
+
+#define DEBUG_TYPE "asm-printer"
+
+namespace llvm {
+
+// Include the auto-generated portion of the assembly writer.
+#define PRINT_ALIAS_INSTR
+#include "AVRGenAsmWriter.inc"
+
+void AVRInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
+ StringRef Annot, const MCSubtargetInfo &STI) {
+ unsigned Opcode = MI->getOpcode();
+
+ // First handle load and store instructions with postinc or predec
+ // of the form "ld reg, X+".
+ // TODO: We should be able to rewrite this using TableGen data.
+ switch (Opcode) {
+ case AVR::LDRdPtr:
+ case AVR::LDRdPtrPi:
+ case AVR::LDRdPtrPd:
+ O << "\tld\t";
+ printOperand(MI, 0, O);
+ O << ", ";
+
+ if (Opcode == AVR::LDRdPtrPd)
+ O << '-';
+
+ printOperand(MI, 1, O);
+
+ if (Opcode == AVR::LDRdPtrPi)
+ O << '+';
+ break;
+ case AVR::STPtrRr:
+ O << "\tst\t";
+ printOperand(MI, 0, O);
+ O << ", ";
+ printOperand(MI, 1, O);
+ break;
+ case AVR::STPtrPiRr:
+ case AVR::STPtrPdRr:
+ O << "\tst\t";
+
+ if (Opcode == AVR::STPtrPdRr)
+ O << '-';
+
+ printOperand(MI, 1, O);
+
+ if (Opcode == AVR::STPtrPiRr)
+ O << '+';
+
+ O << ", ";
+ printOperand(MI, 2, O);
+ break;
+ default:
+ if (!printAliasInstr(MI, O))
+ printInstruction(MI, O);
+
+ printAnnotation(O, Annot);
+ break;
+ }
+}
+
+const char *AVRInstPrinter::getPrettyRegisterName(unsigned RegNum,
+ MCRegisterInfo const &MRI) {
+ // GCC prints register pairs by just printing the lower register
+ // If the register contains a subregister, print it instead
+ if (MRI.getNumSubRegIndices() > 0) {
+ unsigned RegLoNum = MRI.getSubReg(RegNum, AVR::sub_lo);
+ RegNum = (RegLoNum != AVR::NoRegister) ? RegLoNum : RegNum;
+ }
+
+ return getRegisterName(RegNum);
+}
+
+void AVRInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
+ raw_ostream &O) {
+ const MCOperand &Op = MI->getOperand(OpNo);
+ const MCOperandInfo &MOI = this->MII.get(MI->getOpcode()).OpInfo[OpNo];
+
+ if (Op.isReg()) {
+ bool isPtrReg = (MOI.RegClass == AVR::PTRREGSRegClassID) ||
+ (MOI.RegClass == AVR::PTRDISPREGSRegClassID) ||
+ (MOI.RegClass == AVR::ZREGSRegClassID);
+
+ if (isPtrReg) {
+ O << getRegisterName(Op.getReg(), AVR::ptr);
+ } else {
+ O << getPrettyRegisterName(Op.getReg(), MRI);
+ }
+ } else if (Op.isImm()) {
+ O << Op.getImm();
+ } else {
+ assert(Op.isExpr() && "Unknown operand kind in printOperand");
+ O << *Op.getExpr();
+ }
+}
+
+/// This is used to print an immediate value that ends up
+/// being encoded as a pc-relative value.
+void AVRInstPrinter::printPCRelImm(const MCInst *MI, unsigned OpNo,
+ raw_ostream &O) {
+ const MCOperand &Op = MI->getOperand(OpNo);
+
+ if (Op.isImm()) {
+ int64_t Imm = Op.getImm();
+ O << '.';
+
+ // Print a position sign if needed.
+ // Negative values have their sign printed automatically.
+ if (Imm >= 0)
+ O << '+';
+
+ O << Imm;
+ } else {
+ assert(Op.isExpr() && "Unknown pcrel immediate operand");
+ O << *Op.getExpr();
+ }
+}
+
+void AVRInstPrinter::printMemri(const MCInst *MI, unsigned OpNo,
+ raw_ostream &O) {
+ assert(MI->getOperand(OpNo).isReg() && "Expected a register for the first operand");
+
+ const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
+
+ // Print the register.
+ printOperand(MI, OpNo, O);
+
+ // Print the {+,-}offset.
+ if (OffsetOp.isImm()) {
+ int64_t Offset = OffsetOp.getImm();
+
+ if (Offset >= 0)
+ O << '+';
+
+ O << Offset;
+ } else if (OffsetOp.isExpr()) {
+ O << *OffsetOp.getExpr();
+ } else {
+ llvm_unreachable("unknown type for offset");
+ }
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.h b/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.h
new file mode 100644
index 0000000..c9f65b9
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/InstPrinter/AVRInstPrinter.h
@@ -0,0 +1,54 @@
+//===- AVRInstPrinter.h - Convert AVR MCInst to assembly syntax -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class prints an AVR MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_AVR_INST_PRINTER_H
+#define LLVM_AVR_INST_PRINTER_H
+
+#include "llvm/MC/MCInstPrinter.h"
+
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+namespace llvm {
+
+/// Prints AVR instructions to a textual stream.
+class AVRInstPrinter : public MCInstPrinter {
+public:
+ AVRInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
+ const MCRegisterInfo &MRI)
+ : MCInstPrinter(MAI, MII, MRI) {}
+
+ static const char *getPrettyRegisterName(unsigned RegNo,
+ MCRegisterInfo const &MRI);
+
+ void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot,
+ const MCSubtargetInfo &STI) override;
+
+private:
+ static const char *getRegisterName(unsigned RegNo,
+ unsigned AltIdx = AVR::NoRegAltName);
+
+ void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printPCRelImm(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printMemri(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+
+ // Autogenerated by TableGen.
+ void printInstruction(const MCInst *MI, raw_ostream &O);
+ bool printAliasInstr(const MCInst *MI, raw_ostream &O);
+ void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx,
+ unsigned PrintMethodIdx, raw_ostream &O);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_AVR_INST_PRINTER_H
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp
new file mode 100644
index 0000000..081d8b5
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp
@@ -0,0 +1,473 @@
+//===-- AVRAsmBackend.cpp - AVR Asm Backend ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the AVRAsmBackend class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/AVRAsmBackend.h"
+#include "MCTargetDesc/AVRFixupKinds.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+// FIXME: we should be doing checks to make sure asm operands
+// are not out of bounds.
+
+namespace adjust {
+
+using namespace llvm;
+
+void signed_width(unsigned Width, uint64_t Value, std::string Description,
+ const MCFixup &Fixup, MCContext *Ctx = nullptr) {
+ if (!isIntN(Width, Value)) {
+ std::string Diagnostic = "out of range " + Description;
+
+ int64_t Min = minIntN(Width);
+ int64_t Max = maxIntN(Width);
+
+ Diagnostic += " (expected an integer in the range " + std::to_string(Min) +
+ " to " + std::to_string(Max) + ")";
+
+ if (Ctx) {
+ Ctx->reportFatalError(Fixup.getLoc(), Diagnostic);
+ } else {
+ llvm_unreachable(Diagnostic.c_str());
+ }
+ }
+}
+
+void unsigned_width(unsigned Width, uint64_t Value, std::string Description,
+ const MCFixup &Fixup, MCContext *Ctx = nullptr) {
+ if (!isUIntN(Width, Value)) {
+ std::string Diagnostic = "out of range " + Description;
+
+ int64_t Max = maxUIntN(Width);
+
+ Diagnostic += " (expected an integer in the range 0 to " +
+ std::to_string(Max) + ")";
+
+ if (Ctx) {
+ Ctx->reportFatalError(Fixup.getLoc(), Diagnostic);
+ } else {
+ llvm_unreachable(Diagnostic.c_str());
+ }
+ }
+}
+
+/// Adjusts the value of a branch target before fixup application.
+void adjustBranch(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ // We have one extra bit of precision because the value is rightshifted by
+ // one.
+ unsigned_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
+
+ // Rightshifts the value by one.
+ AVR::fixups::adjustBranchTarget(Value);
+}
+
+/// Adjusts the value of a relative branch target before fixup application.
+void adjustRelativeBranch(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ // We have one extra bit of precision because the value is rightshifted by
+ // one.
+ signed_width(Size + 1, Value, std::string("branch target"), Fixup, Ctx);
+
+ Value -= 2;
+
+ // Rightshifts the value by one.
+ AVR::fixups::adjustBranchTarget(Value);
+}
+
+/// 22-bit absolute fixup.
+///
+/// Resolves to:
+/// 1001 kkkk 010k kkkk kkkk kkkk 111k kkkk
+///
+/// Offset of 0 (so the result is left shifted by 3 bits before application).
+void fixup_call(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ adjustBranch(Size, Fixup, Value, Ctx);
+
+ auto top = Value & (0xf00000 << 6); // the top four bits
+ auto middle = Value & (0x1ffff << 5); // the middle 13 bits
+ auto bottom = Value & 0x1f; // end bottom 5 bits
+
+ Value = (top << 6) | (middle << 3) | (bottom << 0);
+}
+
+/// 7-bit PC-relative fixup.
+///
+/// Resolves to:
+/// 0000 00kk kkkk k000
+/// Offset of 0 (so the result is left shifted by 3 bits before application).
+void fixup_7_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ adjustRelativeBranch(Size, Fixup, Value, Ctx);
+
+ // Because the value may be negative, we must mask out the sign bits
+ Value &= 0x7f;
+}
+
+/// 12-bit PC-relative fixup.
+/// Yes, the fixup is 12 bits even though the name says otherwise.
+///
+/// Resolves to:
+/// 0000 kkkk kkkk kkkk
+/// Offset of 0 (so the result isn't left-shifted before application).
+void fixup_13_pcrel(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ adjustRelativeBranch(Size, Fixup, Value, Ctx);
+
+ // Because the value may be negative, we must mask out the sign bits
+ Value &= 0xfff;
+}
+
+/// 6-bit fixup for the immediate operand of the ADIW family of
+/// instructions.
+///
+/// Resolves to:
+/// 0000 0000 kk00 kkkk
+void fixup_6_adiw(const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ unsigned_width(6, Value, std::string("immediate"), Fixup, Ctx);
+
+ Value = ((Value & 0x30) << 2) | (Value & 0x0f);
+}
+
+/// 5-bit port number fixup on the SBIC family of instructions.
+///
+/// Resolves to:
+/// 0000 0000 AAAA A000
+void fixup_port5(const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ unsigned_width(5, Value, std::string("port number"), Fixup, Ctx);
+
+ Value &= 0x1f;
+
+ Value <<= 3;
+}
+
+/// 6-bit port number fixup on the `IN` family of instructions.
+///
+/// Resolves to:
+/// 1011 0AAd dddd AAAA
+void fixup_port6(const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ unsigned_width(6, Value, std::string("port number"), Fixup, Ctx);
+
+ Value = ((Value & 0x30) << 5) | (Value & 0x0f);
+}
+
+/// Adjusts a program memory address.
+/// This is a simple right-shift.
+void pm(uint64_t &Value) {
+ Value >>= 1;
+}
+
+/// Fixups relating to the LDI instruction.
+namespace ldi {
+
+/// Adjusts a value to fix up the immediate of an `LDI Rd, K` instruction.
+///
+/// Resolves to:
+/// 0000 KKKK 0000 KKKK
+/// Offset of 0 (so the result isn't left-shifted before application).
+void fixup(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ uint64_t upper = Value & 0xf0;
+ uint64_t lower = Value & 0x0f;
+
+ Value = (upper << 4) | lower;
+}
+
+void neg(uint64_t &Value) { Value *= -1; }
+
+void lo8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ Value &= 0xff;
+ ldi::fixup(Size, Fixup, Value, Ctx);
+}
+
+void hi8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ Value = (Value & 0xff00) >> 8;
+ ldi::fixup(Size, Fixup, Value, Ctx);
+}
+
+void hh8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ Value = (Value & 0xff0000) >> 16;
+ ldi::fixup(Size, Fixup, Value, Ctx);
+}
+
+void ms8(unsigned Size, const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) {
+ Value = (Value & 0xff000000) >> 24;
+ ldi::fixup(Size, Fixup, Value, Ctx);
+}
+
+} // end of ldi namespace
+} // end of adjust namespace
+
+namespace llvm {
+
+// Prepare value for the target space for it
+void AVRAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx) const {
+ // The size of the fixup in bits.
+ uint64_t Size = AVRAsmBackend::getFixupKindInfo(Fixup.getKind()).TargetSize;
+
+ unsigned Kind = Fixup.getKind();
+
+ switch (Kind) {
+ default:
+ llvm_unreachable("unhandled fixup");
+ case AVR::fixup_7_pcrel:
+ adjust::fixup_7_pcrel(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_13_pcrel:
+ adjust::fixup_13_pcrel(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_call:
+ adjust::fixup_call(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_ldi:
+ adjust::ldi::fixup(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_lo8_ldi:
+ case AVR::fixup_lo8_ldi_pm:
+ if (Kind == AVR::fixup_lo8_ldi_pm) adjust::pm(Value);
+
+ adjust::ldi::lo8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_hi8_ldi:
+ case AVR::fixup_hi8_ldi_pm:
+ if (Kind == AVR::fixup_hi8_ldi_pm) adjust::pm(Value);
+
+ adjust::ldi::hi8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_hh8_ldi:
+ case AVR::fixup_hh8_ldi_pm:
+ if (Kind == AVR::fixup_hh8_ldi_pm) adjust::pm(Value);
+
+ adjust::ldi::hh8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_ms8_ldi:
+ adjust::ldi::ms8(Size, Fixup, Value, Ctx);
+ break;
+
+ case AVR::fixup_lo8_ldi_neg:
+ case AVR::fixup_lo8_ldi_pm_neg:
+ if (Kind == AVR::fixup_lo8_ldi_pm_neg) adjust::pm(Value);
+
+ adjust::ldi::neg(Value);
+ adjust::ldi::lo8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_hi8_ldi_neg:
+ case AVR::fixup_hi8_ldi_pm_neg:
+ if (Kind == AVR::fixup_hi8_ldi_pm_neg) adjust::pm(Value);
+
+ adjust::ldi::neg(Value);
+ adjust::ldi::hi8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_hh8_ldi_neg:
+ case AVR::fixup_hh8_ldi_pm_neg:
+ if (Kind == AVR::fixup_hh8_ldi_pm_neg) adjust::pm(Value);
+
+ adjust::ldi::neg(Value);
+ adjust::ldi::hh8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_ms8_ldi_neg:
+ adjust::ldi::neg(Value);
+ adjust::ldi::ms8(Size, Fixup, Value, Ctx);
+ break;
+ case AVR::fixup_16:
+ adjust::unsigned_width(16, Value, std::string("port number"), Fixup, Ctx);
+
+ Value &= 0xffff;
+ break;
+ case AVR::fixup_6_adiw:
+ adjust::fixup_6_adiw(Fixup, Value, Ctx);
+ break;
+
+ case AVR::fixup_port5:
+ adjust::fixup_port5(Fixup, Value, Ctx);
+ break;
+
+ case AVR::fixup_port6:
+ adjust::fixup_port6(Fixup, Value, Ctx);
+ break;
+
+ // Fixups which do not require adjustments.
+ case FK_Data_2:
+ case FK_Data_4:
+ case FK_Data_8:
+ break;
+
+ case FK_GPRel_4:
+ llvm_unreachable("don't know how to adjust this fixup");
+ break;
+ }
+}
+
+MCObjectWriter *AVRAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const {
+ return createAVRELFObjectWriter(OS,
+ MCELFObjectTargetWriter::getOSABI(OSType));
+}
+
+void AVRAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
+ unsigned DataSize, uint64_t Value,
+ bool IsPCRel) const {
+ if (Value == 0)
+ return; // Doesn't change encoding.
+
+ MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
+
+ // The number of bits in the fixup mask
+ auto NumBits = Info.TargetSize + Info.TargetOffset;
+ auto NumBytes = (NumBits / 8) + ((NumBits % 8) == 0 ? 0 : 1);
+
+ // Shift the value into position.
+ Value <<= Info.TargetOffset;
+
+ unsigned Offset = Fixup.getOffset();
+ assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!");
+
+ // For each byte of the fragment that the fixup touches, mask in the
+ // bits from the fixup value.
+ for (unsigned i = 0; i < NumBytes; ++i) {
+ uint8_t mask = (((Value >> (i * 8)) & 0xff));
+ Data[Offset + i] |= mask;
+ }
+}
+
+MCFixupKindInfo const &AVRAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
+ // NOTE: Many AVR fixups work on sets of non-contignous bits. We work around
+ // this by saying that the fixup is the size of the entire instruction.
+ const static MCFixupKindInfo Infos[AVR::NumTargetFixupKinds] = {
+ // This table *must* be in same the order of fixup_* kinds in
+ // AVRFixupKinds.h.
+ //
+ // name offset bits flags
+ {"fixup_32", 0, 32, 0},
+
+ {"fixup_7_pcrel", 3, 7, MCFixupKindInfo::FKF_IsPCRel},
+ {"fixup_13_pcrel", 0, 12, MCFixupKindInfo::FKF_IsPCRel},
+
+ {"fixup_16", 0, 16, 0},
+ {"fixup_16_pm", 0, 16, 0},
+
+ {"fixup_ldi", 0, 8, 0},
+
+ {"fixup_lo8_ldi", 0, 8, 0},
+ {"fixup_hi8_ldi", 0, 8, 0},
+ {"fixup_hh8_ldi", 0, 8, 0},
+ {"fixup_ms8_ldi", 0, 8, 0},
+
+ {"fixup_lo8_ldi_neg", 0, 8, 0},
+ {"fixup_hi8_ldi_neg", 0, 8, 0},
+ {"fixup_hh8_ldi_neg", 0, 8, 0},
+ {"fixup_ms8_ldi_neg", 0, 8, 0},
+
+ {"fixup_lo8_ldi_pm", 0, 8, 0},
+ {"fixup_hi8_ldi_pm", 0, 8, 0},
+ {"fixup_hh8_ldi_pm", 0, 8, 0},
+
+ {"fixup_lo8_ldi_pm_neg", 0, 8, 0},
+ {"fixup_hi8_ldi_pm_neg", 0, 8, 0},
+ {"fixup_hh8_ldi_pm_neg", 0, 8, 0},
+
+ {"fixup_call", 0, 22, 0},
+
+ {"fixup_6", 0, 16, 0}, // non-contiguous
+ {"fixup_6_adiw", 0, 6, 0},
+
+ {"fixup_lo8_ldi_gs", 0, 8, 0},
+ {"fixup_hi8_ldi_gs", 0, 8, 0},
+
+ {"fixup_8", 0, 8, 0},
+ {"fixup_8_lo8", 0, 8, 0},
+ {"fixup_8_hi8", 0, 8, 0},
+ {"fixup_8_hlo8", 0, 8, 0},
+
+ {"fixup_sym_diff", 0, 32, 0},
+ {"fixup_16_ldst", 0, 16, 0},
+
+ {"fixup_lds_sts_16", 0, 16, 0},
+
+ {"fixup_port6", 0, 16, 0}, // non-contiguous
+ {"fixup_port5", 3, 5, 0},
+ };
+
+ if (Kind < FirstTargetFixupKind)
+ return MCAsmBackend::getFixupKindInfo(Kind);
+
+ assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
+ "Invalid kind!");
+
+ return Infos[Kind - FirstTargetFixupKind];
+}
+
+bool AVRAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
+ // If the count is not 2-byte aligned, we must be writing data into the text
+ // section (otherwise we have unaligned instructions, and thus have far
+ // bigger problems), so just write zeros instead.
+ assert((Count % 2) == 0 && "NOP instructions must be 2 bytes");
+
+ OW->WriteZeros(Count);
+ return true;
+}
+
+void AVRAsmBackend::processFixupValue(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFixup &Fixup,
+ const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &IsResolved) {
+ switch ((unsigned) Fixup.getKind()) {
+ // Fixups which should always be recorded as relocations.
+ case AVR::fixup_7_pcrel:
+ case AVR::fixup_13_pcrel:
+ case AVR::fixup_call:
+ IsResolved = false;
+ break;
+ default:
+ // Parsed LLVM-generated temporary labels are already
+ // adjusted for instruction size, but normal labels aren't.
+ //
+ // To handle both cases, we simply un-adjust the temporary label
+ // case so it acts like all other labels.
+ if (Target.getSymA()->getSymbol().isTemporary())
+ Value += 2;
+
+ adjustFixupValue(Fixup, Value, &Asm.getContext());
+ break;
+ }
+}
+
+MCAsmBackend *createAVRAsmBackend(const Target &T, const MCRegisterInfo &MRI,
+ const Triple &TT, StringRef CPU,
+ const llvm::MCTargetOptions &TO) {
+ return new AVRAsmBackend(TT.getOS());
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.h b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.h
new file mode 100644
index 0000000..7ff4b8f
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.h
@@ -0,0 +1,78 @@
+//===-- AVRAsmBackend.h - AVR Asm Backend --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// \file The AVR assembly backend implementation.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#ifndef LLVM_AVR_ASM_BACKEND_H
+#define LLVM_AVR_ASM_BACKEND_H
+
+#include "MCTargetDesc/AVRFixupKinds.h"
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCAsmBackend.h"
+
+namespace llvm {
+
+class MCAssembler;
+class MCObjectWriter;
+class Target;
+
+struct MCFixupKindInfo;
+
+/// Utilities for manipulating generated AVR machine code.
+class AVRAsmBackend : public MCAsmBackend {
+public:
+
+ AVRAsmBackend(Triple::OSType OSType)
+ : MCAsmBackend(), OSType(OSType) {}
+
+ void adjustFixupValue(const MCFixup &Fixup, uint64_t &Value,
+ MCContext *Ctx = nullptr) const;
+
+ MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override;
+
+ void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
+ uint64_t Value, bool IsPCRel) const override;
+
+ const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
+
+ unsigned getNumFixupKinds() const override {
+ return AVR::NumTargetFixupKinds;
+ }
+
+ bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
+
+ bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
+ const MCRelaxableFragment *DF,
+ const MCAsmLayout &Layout) const override {
+ llvm_unreachable("RelaxInstruction() unimplemented");
+ return false;
+ }
+
+ void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
+ MCInst &Res) const override {}
+
+ bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override;
+
+ void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFixup &Fixup, const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &IsResolved) override;
+
+private:
+ Triple::OSType OSType;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_AVR_ASM_BACKEND_H
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp
new file mode 100644
index 0000000..161f305
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp
@@ -0,0 +1,127 @@
+//===-- AVRELFObjectWriter.cpp - AVR ELF Writer ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/AVRFixupKinds.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace llvm {
+
+/// Writes AVR machine code into an ELF32 object file.
+class AVRELFObjectWriter : public MCELFObjectTargetWriter {
+public:
+ AVRELFObjectWriter(uint8_t OSABI);
+
+ virtual ~AVRELFObjectWriter() {}
+
+ unsigned getRelocType(MCContext &Ctx,
+ const MCValue &Target,
+ const MCFixup &Fixup,
+ bool IsPCRel) const override;
+};
+
+AVRELFObjectWriter::AVRELFObjectWriter(uint8_t OSABI)
+ : MCELFObjectTargetWriter(false, OSABI, ELF::EM_AVR, true, false) {}
+
+unsigned AVRELFObjectWriter::getRelocType(MCContext &Ctx,
+ const MCValue &Target,
+ const MCFixup &Fixup,
+ bool IsPCRel) const {
+ switch ((unsigned) Fixup.getKind()) {
+ case FK_Data_1:
+ case FK_Data_4:
+ llvm_unreachable("unsupported relocation type");
+ case FK_Data_2:
+ return ELF::R_AVR_16_PM;
+ case AVR::fixup_32:
+ return ELF::R_AVR_32;
+ case AVR::fixup_7_pcrel:
+ return ELF::R_AVR_7_PCREL;
+ case AVR::fixup_13_pcrel:
+ return ELF::R_AVR_13_PCREL;
+ case AVR::fixup_16:
+ return ELF::R_AVR_16;
+ case AVR::fixup_16_pm:
+ return ELF::R_AVR_16_PM;
+ case AVR::fixup_lo8_ldi:
+ return ELF::R_AVR_LO8_LDI;
+ case AVR::fixup_hi8_ldi:
+ return ELF::R_AVR_HI8_LDI;
+ case AVR::fixup_hh8_ldi:
+ return ELF::R_AVR_HH8_LDI;
+ case AVR::fixup_lo8_ldi_neg:
+ return ELF::R_AVR_LO8_LDI_NEG;
+ case AVR::fixup_hi8_ldi_neg:
+ return ELF::R_AVR_HI8_LDI_NEG;
+ case AVR::fixup_hh8_ldi_neg:
+ return ELF::R_AVR_HH8_LDI_NEG;
+ case AVR::fixup_lo8_ldi_pm:
+ return ELF::R_AVR_LO8_LDI_PM;
+ case AVR::fixup_hi8_ldi_pm:
+ return ELF::R_AVR_HI8_LDI_PM;
+ case AVR::fixup_hh8_ldi_pm:
+ return ELF::R_AVR_HH8_LDI_PM;
+ case AVR::fixup_lo8_ldi_pm_neg:
+ return ELF::R_AVR_LO8_LDI_PM_NEG;
+ case AVR::fixup_hi8_ldi_pm_neg:
+ return ELF::R_AVR_HI8_LDI_PM_NEG;
+ case AVR::fixup_hh8_ldi_pm_neg:
+ return ELF::R_AVR_HH8_LDI_PM_NEG;
+ case AVR::fixup_call:
+ return ELF::R_AVR_CALL;
+ case AVR::fixup_ldi:
+ return ELF::R_AVR_LDI;
+ case AVR::fixup_6:
+ return ELF::R_AVR_6;
+ case AVR::fixup_6_adiw:
+ return ELF::R_AVR_6_ADIW;
+ case AVR::fixup_ms8_ldi:
+ return ELF::R_AVR_MS8_LDI;
+ case AVR::fixup_ms8_ldi_neg:
+ return ELF::R_AVR_MS8_LDI_NEG;
+ case AVR::fixup_lo8_ldi_gs:
+ return ELF::R_AVR_LO8_LDI_GS;
+ case AVR::fixup_hi8_ldi_gs:
+ return ELF::R_AVR_HI8_LDI_GS;
+ case AVR::fixup_8:
+ return ELF::R_AVR_8;
+ case AVR::fixup_8_lo8:
+ return ELF::R_AVR_8_LO8;
+ case AVR::fixup_8_hi8:
+ return ELF::R_AVR_8_HI8;
+ case AVR::fixup_8_hlo8:
+ return ELF::R_AVR_8_HLO8;
+ case AVR::fixup_sym_diff:
+ return ELF::R_AVR_SYM_DIFF;
+ case AVR::fixup_16_ldst:
+ return ELF::R_AVR_16_LDST;
+ case AVR::fixup_lds_sts_16:
+ return ELF::R_AVR_LDS_STS_16;
+ case AVR::fixup_port6:
+ return ELF::R_AVR_PORT6;
+ case AVR::fixup_port5:
+ return ELF::R_AVR_PORT5;
+ default:
+ llvm_unreachable("invalid fixup kind!");
+ }
+}
+
+MCObjectWriter *createAVRELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI) {
+ MCELFObjectTargetWriter *MOTW = new AVRELFObjectWriter(OSABI);
+ return createELFObjectWriter(MOTW, OS, true);
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRFixupKinds.h b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRFixupKinds.h
new file mode 100644
index 0000000..d3bd52d
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRFixupKinds.h
@@ -0,0 +1,149 @@
+//===-- AVRFixupKinds.h - AVR Specific Fixup Entries ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_AVR_FIXUP_KINDS_H
+#define LLVM_AVR_FIXUP_KINDS_H
+
+#include "llvm/MC/MCFixup.h"
+
+namespace llvm {
+namespace AVR {
+
+/// The set of supported fixups.
+///
+/// Although most of the current fixup types reflect a unique relocation
+/// one can have multiple fixup types for a given relocation and thus need
+/// to be uniquely named.
+///
+/// \note This table *must* be in the same order of
+/// MCFixupKindInfo Infos[AVR::NumTargetFixupKinds]
+/// in `AVRAsmBackend.cpp`.
+enum Fixups {
+ /// A 32-bit AVR fixup.
+ fixup_32 = FirstTargetFixupKind,
+
+ /// A 7-bit PC-relative fixup for the family of conditional
+ /// branches which take 7-bit targets (BRNE,BRGT,etc).
+ fixup_7_pcrel,
+ /// A 12-bit PC-relative fixup for the family of branches
+ /// which take 12-bit targets (RJMP,RCALL,etc).
+ /// \note Although the fixup is labelled as 13 bits, it
+ /// is actually only encoded in 12. The reason for
+ /// The nonmenclature is that AVR branch targets are
+ /// rightshifted by 1, because instructions are always
+ /// aligned to 2 bytes, so the 0'th bit is always 0.
+ /// This way there is 13-bits of precision.
+ fixup_13_pcrel,
+
+ /// A 16-bit address.
+ fixup_16,
+ /// A 16-bit program memory address.
+ fixup_16_pm,
+
+ /// Replaces the 8-bit immediate with another value.
+ fixup_ldi,
+
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the lower 8 bits of a 16-bit value (bits 0-7).
+ fixup_lo8_ldi,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a 16-bit value (bits 8-15).
+ fixup_hi8_ldi,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a 24-bit value (bits 16-23).
+ fixup_hh8_ldi,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a 32-bit value (bits 24-31).
+ fixup_ms8_ldi,
+
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the lower 8 bits of a negated 16-bit value (bits 0-7).
+ fixup_lo8_ldi_neg,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a negated 16-bit value (bits 8-15).
+ fixup_hi8_ldi_neg,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a negated negated 24-bit value (bits 16-23).
+ fixup_hh8_ldi_neg,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a negated negated 32-bit value (bits 24-31).
+ fixup_ms8_ldi_neg,
+
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the lower 8 bits of a 16-bit program memory address value (bits 0-7).
+ fixup_lo8_ldi_pm,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a 16-bit program memory address value (bits
+ /// 8-15).
+ fixup_hi8_ldi_pm,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a 24-bit program memory address value (bits
+ /// 16-23).
+ fixup_hh8_ldi_pm,
+
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the lower 8 bits of a negated 16-bit program memory address value
+ /// (bits 0-7).
+ fixup_lo8_ldi_pm_neg,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a negated 16-bit program memory address value
+ /// (bits 8-15).
+ fixup_hi8_ldi_pm_neg,
+ /// Replaces the immediate operand of a 16-bit `Rd, K` instruction
+ /// with the upper 8 bits of a negated 24-bit program memory address value
+ /// (bits 16-23).
+ fixup_hh8_ldi_pm_neg,
+
+ /// A 22-bit fixup for the target of a `CALL k` or `JMP k` instruction.
+ fixup_call,
+
+ fixup_6,
+ /// A symbol+addr fixup for the `LDD <x>+<n>, <r>" family of instructions.
+ fixup_6_adiw,
+
+ fixup_lo8_ldi_gs,
+ fixup_hi8_ldi_gs,
+
+ fixup_8,
+ fixup_8_lo8,
+ fixup_8_hi8,
+ fixup_8_hlo8,
+
+ /// Fixup to calculate the difference between two symbols.
+ /// Is the only stateful fixup. We do not support it yet.
+ fixup_sym_diff,
+ fixup_16_ldst,
+
+ fixup_lds_sts_16,
+
+ /// A 6-bit port address.
+ fixup_port6,
+ /// A 5-bit port address.
+ fixup_port5,
+
+ // Marker
+ LastTargetFixupKind,
+ NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
+};
+
+namespace fixups {
+
+/// Adjusts the value of a branch target.
+/// All branch targets in AVR are rightshifted by 1 to take advantage
+/// of the fact that all instructions are aligned to addresses of size
+/// 2, so bit 0 of an address is always 0. This gives us another bit
+/// of precision.
+/// \param[in,out] The target to adjust.
+template <typename T> inline void adjustBranchTarget(T &val) { val >>= 1; }
+
+} // end of namespace fixups
+}
+} // end of namespace llvm::AVR
+
+#endif // LLVM_AVR_FIXUP_KINDS_H
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
new file mode 100644
index 0000000..e6dc886
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
@@ -0,0 +1,304 @@
+//===-- AVRMCCodeEmitter.cpp - Convert AVR Code to Machine Code -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the AVRMCCodeEmitter class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRMCCodeEmitter.h"
+
+#include "MCTargetDesc/AVRMCExpr.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "mccodeemitter"
+
+#define GET_INSTRMAP_INFO
+#include "AVRGenInstrInfo.inc"
+#undef GET_INSTRMAP_INFO
+
+namespace llvm {
+
+/// Performs a post-encoding step on a `LD` or `ST` instruction.
+///
+/// The encoding of the LD/ST family of instructions is inconsistent w.r.t
+/// the pointer register and the addressing mode.
+///
+/// The permutations of the format are as followed:
+/// ld Rd, X `1001 000d dddd 1100`
+/// ld Rd, X+ `1001 000d dddd 1101`
+/// ld Rd, -X `1001 000d dddd 1110`
+///
+/// ld Rd, Y `1000 000d dddd 1000`
+/// ld Rd, Y+ `1001 000d dddd 1001`
+/// ld Rd, -Y `1001 000d dddd 1010`
+///
+/// ld Rd, Z `1000 000d dddd 0000`
+/// ld Rd, Z+ `1001 000d dddd 0001`
+/// ld Rd, -Z `1001 000d dddd 0010`
+/// ^
+/// |
+/// Note this one inconsistent bit - it is 1 sometimes and 0 at other times.
+/// There is no logical pattern. Looking at a truth table, the following
+/// formula can be derived to fit the pattern:
+//
+/// ```
+/// inconsistent_bit = is_predec OR is_postinc OR is_reg_x
+/// ```
+//
+/// We manually set this bit in this post encoder method.
+unsigned
+AVRMCCodeEmitter::loadStorePostEncoder(const MCInst &MI, unsigned EncodedValue,
+ const MCSubtargetInfo &STI) const {
+
+ assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg() &&
+ "the load/store operands must be registers");
+
+ unsigned Opcode = MI.getOpcode();
+
+ // check whether either of the registers are the X pointer register.
+ bool IsRegX = MI.getOperand(0).getReg() == AVR::R27R26 ||
+ MI.getOperand(1).getReg() == AVR::R27R26;
+
+ bool IsPredec = Opcode == AVR::LDRdPtrPd || Opcode == AVR::STPtrPdRr;
+ bool IsPostinc = Opcode == AVR::LDRdPtrPi || Opcode == AVR::STPtrPiRr;
+
+ // Check if we need to set the inconsistent bit
+ if (IsRegX || IsPredec || IsPostinc) {
+ EncodedValue |= (1 << 12);
+ }
+
+ return EncodedValue;
+}
+
+template <AVR::Fixups Fixup>
+unsigned
+AVRMCCodeEmitter::encodeRelCondBrTarget(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+
+ if (MO.isExpr()) {
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(),
+ MCFixupKind(Fixup), MI.getLoc()));
+ return 0;
+ }
+
+ assert(MO.isImm());
+
+ // Take the size of the current instruction away.
+ // With labels, this is implicitly done.
+ auto target = MO.getImm();
+ AVR::fixups::adjustBranchTarget(target);
+ return target;
+}
+
+unsigned AVRMCCodeEmitter::encodeLDSTPtrReg(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ auto MO = MI.getOperand(OpNo);
+
+ // The operand should be a pointer register.
+ assert(MO.isReg());
+
+ switch (MO.getReg()) {
+ case AVR::R27R26: return 0x03; // X: 0b11
+ case AVR::R29R28: return 0x02; // Y: 0b10
+ case AVR::R31R30: return 0x00; // Z: 0b00
+ default:
+ llvm_unreachable("invalid pointer register");
+ }
+}
+
+/// Encodes a `memri` operand.
+/// The operand is 7-bits.
+/// * The lower 6 bits is the immediate
+/// * The upper bit is the pointer register bit (Z=0,Y=1)
+unsigned AVRMCCodeEmitter::encodeMemri(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ auto RegOp = MI.getOperand(OpNo);
+ auto OffsetOp = MI.getOperand(OpNo + 1);
+
+ assert(RegOp.isReg() && "Expected register operand");
+
+ uint8_t RegBit = 0;
+
+ switch (RegOp.getReg()) {
+ default:
+ llvm_unreachable("Expected either Y or Z register");
+ case AVR::R31R30:
+ RegBit = 0;
+ break; // Z register
+ case AVR::R29R28:
+ RegBit = 1;
+ break; // Y register
+ }
+
+ int8_t OffsetBits;
+
+ if (OffsetOp.isImm()) {
+ OffsetBits = OffsetOp.getImm();
+ } else if (OffsetOp.isExpr()) {
+ OffsetBits = 0;
+ Fixups.push_back(MCFixup::create(0, OffsetOp.getExpr(),
+ MCFixupKind(AVR::fixup_6), MI.getLoc()));
+ } else {
+ llvm_unreachable("invalid value for offset");
+ }
+
+ return (RegBit << 6) | OffsetBits;
+}
+
+unsigned AVRMCCodeEmitter::encodeComplement(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ // The operand should be an immediate.
+ assert(MI.getOperand(OpNo).isImm());
+
+ auto Imm = MI.getOperand(OpNo).getImm();
+ return (~0) - Imm;
+}
+
+template <AVR::Fixups Fixup>
+unsigned AVRMCCodeEmitter::encodeImm(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ auto MO = MI.getOperand(OpNo);
+
+ if (MO.isExpr()) {
+ if (isa<AVRMCExpr>(MO.getExpr())) {
+ // If the expression is already an AVRMCExpr (i.e. a lo8(symbol),
+ // we shouldn't perform any more fixups. Without this check, we would
+ // instead create a fixup to the symbol named 'lo8(symbol)' which
+ // is not correct.
+ return getExprOpValue(MO.getExpr(), Fixups, STI);
+ }
+
+ MCFixupKind FixupKind = static_cast<MCFixupKind>(Fixup);
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(), FixupKind, MI.getLoc()));
+
+ return 0;
+ }
+
+ assert(MO.isImm());
+ return MO.getImm();
+}
+
+unsigned AVRMCCodeEmitter::encodeCallTarget(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ auto MO = MI.getOperand(OpNo);
+
+ if (MO.isExpr()) {
+ MCFixupKind FixupKind = static_cast<MCFixupKind>(AVR::fixup_call);
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(), FixupKind, MI.getLoc()));
+ return 0;
+ }
+
+ assert(MO.isImm());
+
+ auto Target = MO.getImm();
+ AVR::fixups::adjustBranchTarget(Target);
+ return Target;
+}
+
+unsigned AVRMCCodeEmitter::getExprOpValue(const MCExpr *Expr,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+
+ MCExpr::ExprKind Kind = Expr->getKind();
+
+ if (Kind == MCExpr::Binary) {
+ Expr = static_cast<const MCBinaryExpr *>(Expr)->getLHS();
+ Kind = Expr->getKind();
+ }
+
+ if (Kind == MCExpr::Target) {
+ AVRMCExpr const *AVRExpr = cast<AVRMCExpr>(Expr);
+ int64_t Result;
+ if (AVRExpr->evaluateAsConstant(Result)) {
+ return Result;
+ }
+
+ MCFixupKind FixupKind = static_cast<MCFixupKind>(AVRExpr->getFixupKind());
+ Fixups.push_back(MCFixup::create(0, AVRExpr, FixupKind));
+ return 0;
+ }
+
+ assert(Kind == MCExpr::SymbolRef);
+ return 0;
+}
+
+unsigned AVRMCCodeEmitter::getMachineOpValue(const MCInst &MI,
+ const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ if (MO.isReg()) return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
+ if (MO.isImm()) return static_cast<unsigned>(MO.getImm());
+
+ if (MO.isFPImm())
+ return static_cast<unsigned>(APFloat(MO.getFPImm())
+ .bitcastToAPInt()
+ .getHiBits(32)
+ .getLimitedValue());
+
+ // MO must be an Expr.
+ assert(MO.isExpr());
+
+ return getExprOpValue(MO.getExpr(), Fixups, STI);
+}
+
+void AVRMCCodeEmitter::emitInstruction(uint64_t Val, unsigned Size,
+ const MCSubtargetInfo &STI,
+ raw_ostream &OS) const {
+ const uint16_t *Words = reinterpret_cast<uint16_t const *>(&Val);
+ size_t WordCount = Size / 2;
+
+ for (int64_t i = WordCount - 1; i >= 0; --i) {
+ uint16_t Word = Words[i];
+
+ OS << (uint8_t) ((Word & 0x00ff) >> 0);
+ OS << (uint8_t) ((Word & 0xff00) >> 8);
+ }
+}
+
+void AVRMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
+
+ // Get byte count of instruction
+ unsigned Size = Desc.getSize();
+
+ assert(Size > 0 && "Instruction size cannot be zero");
+
+ uint64_t BinaryOpCode = getBinaryCodeForInstr(MI, Fixups, STI);
+ emitInstruction(BinaryOpCode, Size, STI, OS);
+}
+
+MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII,
+ const MCRegisterInfo &MRI,
+ MCContext &Ctx) {
+ return new AVRMCCodeEmitter(MCII, Ctx);
+}
+
+#include "AVRGenMCCodeEmitter.inc"
+
+} // end of namespace llvm
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.h b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.h
new file mode 100644
index 0000000..5fa425c
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.h
@@ -0,0 +1,115 @@
+//===-- AVRMCCodeEmitter.h - Convert AVR Code to Machine Code -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AVRMCCodeEmitter class.
+//
+//===----------------------------------------------------------------------===//
+//
+
+#ifndef LLVM_AVR_CODE_EMITTER_H
+#define LLVM_AVR_CODE_EMITTER_H
+
+#include "AVRFixupKinds.h"
+
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/Support/DataTypes.h"
+
+#define GET_INSTRINFO_OPERAND_TYPES_ENUM
+#include "AVRGenInstrInfo.inc"
+
+namespace llvm {
+
+class MCContext;
+class MCExpr;
+class MCFixup;
+class MCInst;
+class MCInstrInfo;
+class MCOperand;
+class MCSubtargetInfo;
+class raw_ostream;
+
+/// Writes AVR machine code to a stream.
+class AVRMCCodeEmitter : public MCCodeEmitter {
+public:
+ AVRMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)
+ : MCII(MCII), Ctx(Ctx) {}
+
+private:
+ /// Finishes up encoding an LD/ST instruction.
+ /// The purpose of this function is to set an bit in the instruction
+ /// which follows no logical pattern. See the implementation for details.
+ unsigned loadStorePostEncoder(const MCInst &MI, unsigned EncodedValue,
+ const MCSubtargetInfo &STI) const;
+
+ /// Gets the encoding for a conditional branch target.
+ template <AVR::Fixups Fixup>
+ unsigned encodeRelCondBrTarget(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Encodes the `PTRREGS` operand to a load or store instruction.
+ unsigned encodeLDSTPtrReg(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Encodes a `register+immediate` operand for `LDD`/`STD`.
+ unsigned encodeMemri(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Takes the compliment of a number (~0 - val).
+ unsigned encodeComplement(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Encodes an immediate value with a given fixup.
+ template <AVR::Fixups Fixup>
+ unsigned encodeImm(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Gets the encoding of the target for the `CALL k` instruction.
+ unsigned encodeCallTarget(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// TableGen'ed function to get the binary encoding for an instruction.
+ uint64_t getBinaryCodeForInstr(const MCInst &MI,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ unsigned getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// Returns the binary encoding of operand.
+ ///
+ /// If the machine operand requires relocation, the relocation is recorded
+ /// and zero is returned.
+ unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ void emitInstruction(uint64_t Val, unsigned Size, const MCSubtargetInfo &STI,
+ raw_ostream &OS) const;
+
+ void encodeInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const override;
+
+ AVRMCCodeEmitter(const AVRMCCodeEmitter &) = delete;
+ void operator=(const AVRMCCodeEmitter &) = delete;
+
+ const MCInstrInfo &MCII;
+ MCContext &Ctx;
+};
+
+} // end namespace of llvm.
+
+#endif // LLVM_AVR_CODE_EMITTER_H
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp
new file mode 100644
index 0000000..400296b
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp
@@ -0,0 +1,189 @@
+//===-- AVRMCExpr.cpp - AVR specific MC expression classes ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRMCExpr.h"
+
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/MC/MCAsmLayout.h"
+
+namespace llvm {
+
+namespace {
+
+const struct ModifierEntry {
+ const char * const Spelling;
+ AVRMCExpr::VariantKind VariantKind;
+} ModifierNames[] = {
+ {"lo8", AVRMCExpr::VK_AVR_LO8}, {"hi8", AVRMCExpr::VK_AVR_HI8},
+ {"hh8", AVRMCExpr::VK_AVR_HH8}, // synonym with hlo8
+ {"hlo8", AVRMCExpr::VK_AVR_HH8}, {"hhi8", AVRMCExpr::VK_AVR_HHI8},
+
+ {"pm_lo8", AVRMCExpr::VK_AVR_PM_LO8}, {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8},
+ {"pm_hh8", AVRMCExpr::VK_AVR_PM_HH8},
+};
+
+} // end of anonymous namespace
+
+const AVRMCExpr *AVRMCExpr::create(VariantKind Kind, const MCExpr *Expr,
+ bool Negated, MCContext &Ctx) {
+ return new (Ctx) AVRMCExpr(Kind, Expr, Negated);
+}
+
+void AVRMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
+ assert(Kind != VK_AVR_None);
+
+ if (isNegated())
+ OS << '-';
+
+ OS << getName() << '(';
+ getSubExpr()->print(OS, MAI);
+ OS << ')';
+}
+
+bool AVRMCExpr::evaluateAsConstant(int64_t &Result) const {
+ MCValue Value;
+
+ bool isRelocatable =
+ getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr);
+
+ if (!isRelocatable)
+ return false;
+
+ if (Value.isAbsolute()) {
+ Result = evaluateAsInt64(Value.getConstant());
+ return true;
+ }
+
+ return false;
+}
+
+bool AVRMCExpr::evaluateAsRelocatableImpl(MCValue &Result,
+ const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const {
+ MCValue Value;
+ bool isRelocatable = SubExpr->evaluateAsRelocatable(Value, Layout, Fixup);
+
+ if (!isRelocatable)
+ return false;
+
+ if (Value.isAbsolute()) {
+ Result = MCValue::get(evaluateAsInt64(Value.getConstant()));
+ } else {
+ if (!Layout) return false;
+
+ MCContext &Context = Layout->getAssembler().getContext();
+ const MCSymbolRefExpr *Sym = Value.getSymA();
+ MCSymbolRefExpr::VariantKind Modifier = Sym->getKind();
+ if (Modifier != MCSymbolRefExpr::VK_None)
+ return false;
+
+ Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context);
+ Result = MCValue::get(Sym, Value.getSymB(), Value.getConstant());
+ }
+
+ return true;
+}
+
+int64_t AVRMCExpr::evaluateAsInt64(int64_t Value) const {
+ if (Negated)
+ Value *= -1;
+
+ switch (Kind) {
+ case AVRMCExpr::VK_AVR_LO8:
+ break;
+ case AVRMCExpr::VK_AVR_HI8:
+ Value >>= 8;
+ break;
+ case AVRMCExpr::VK_AVR_HH8:
+ Value >>= 16;
+ break;
+ case AVRMCExpr::VK_AVR_HHI8:
+ Value >>= 24;
+ break;
+ case AVRMCExpr::VK_AVR_PM_LO8:
+ Value >>= 1;
+ break;
+ case AVRMCExpr::VK_AVR_PM_HI8:
+ Value >>= 9;
+ break;
+ case AVRMCExpr::VK_AVR_PM_HH8:
+ Value >>= 17;
+ break;
+
+ case AVRMCExpr::VK_AVR_None:
+ llvm_unreachable("Uninitialized expression.");
+ }
+ return static_cast<uint64_t>(Value) & 0xff;
+}
+
+AVR::Fixups AVRMCExpr::getFixupKind() const {
+ AVR::Fixups Kind = AVR::Fixups::LastTargetFixupKind;
+
+ switch (getKind()) {
+ case VK_AVR_LO8:
+ Kind = isNegated() ? AVR::fixup_lo8_ldi_neg : AVR::fixup_lo8_ldi;
+ break;
+ case VK_AVR_HI8:
+ Kind = isNegated() ? AVR::fixup_hi8_ldi_neg : AVR::fixup_hi8_ldi;
+ break;
+ case VK_AVR_HH8:
+ Kind = isNegated() ? AVR::fixup_hh8_ldi_neg : AVR::fixup_hh8_ldi;
+ break;
+ case VK_AVR_HHI8:
+ Kind = isNegated() ? AVR::fixup_ms8_ldi_neg : AVR::fixup_ms8_ldi;
+ break;
+
+ case VK_AVR_PM_LO8:
+ Kind = isNegated() ? AVR::fixup_lo8_ldi_pm_neg : AVR::fixup_lo8_ldi_pm;
+ break;
+ case VK_AVR_PM_HI8:
+ Kind = isNegated() ? AVR::fixup_hi8_ldi_pm_neg : AVR::fixup_hi8_ldi_pm;
+ break;
+ case VK_AVR_PM_HH8:
+ Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm;
+ break;
+
+ case VK_AVR_None:
+ llvm_unreachable("Uninitialized expression");
+ }
+
+ return Kind;
+}
+
+void AVRMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
+ Streamer.visitUsedExpr(*getSubExpr());
+}
+
+const char *AVRMCExpr::getName() const {
+ const auto &Modifier = std::find_if(
+ std::begin(ModifierNames), std::end(ModifierNames),
+ [this](ModifierEntry const &Mod) { return Mod.VariantKind == Kind; });
+
+ if (Modifier != std::end(ModifierNames)) {
+ return Modifier->Spelling;
+ }
+ return nullptr;
+}
+
+AVRMCExpr::VariantKind AVRMCExpr::getKindByName(StringRef Name) {
+ const auto &Modifier = std::find_if(
+ std::begin(ModifierNames), std::end(ModifierNames),
+ [&Name](ModifierEntry const &Mod) { return Mod.Spelling == Name; });
+
+ if (Modifier != std::end(ModifierNames)) {
+ return Modifier->VariantKind;
+ }
+ return VK_AVR_None;
+}
+
+} // end of namespace llvm
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h
new file mode 100644
index 0000000..be565a8
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h
@@ -0,0 +1,88 @@
+//===-- AVRMCExpr.h - AVR specific MC expression classes --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_AVR_MCEXPR_H
+#define LLVM_AVR_MCEXPR_H
+
+#include "llvm/MC/MCExpr.h"
+
+#include "MCTargetDesc/AVRFixupKinds.h"
+
+namespace llvm {
+
+/// A expression in AVR machine code.
+class AVRMCExpr : public MCTargetExpr {
+public:
+ /// Specifies the type of an expression.
+ enum VariantKind {
+ VK_AVR_None,
+
+ VK_AVR_HI8, ///< Corresponds to `hi8()`.
+ VK_AVR_LO8, ///< Corresponds to `lo8()`.
+ VK_AVR_HH8, ///< Corresponds to `hlo8() and hh8()`.
+ VK_AVR_HHI8, ///< Corresponds to `hhi8()`.
+
+ VK_AVR_PM_LO8, ///< Corresponds to `pm_lo8()`.
+ VK_AVR_PM_HI8, ///< Corresponds to `pm_hi8()`.
+ VK_AVR_PM_HH8 ///< Corresponds to `pm_hh8()`.
+ };
+
+public:
+ /// Creates an AVR machine code expression.
+ static const AVRMCExpr *create(VariantKind Kind, const MCExpr *Expr,
+ bool isNegated, MCContext &Ctx);
+
+ /// Gets the type of the expression.
+ VariantKind getKind() const { return Kind; }
+ /// Gets the name of the expression.
+ const char *getName() const;
+ const MCExpr *getSubExpr() const { return SubExpr; }
+ /// Gets the fixup which corresponds to the expression.
+ AVR::Fixups getFixupKind() const;
+ /// Evaluates the fixup as a constant value.
+ bool evaluateAsConstant(int64_t &Result) const;
+
+ bool isNegated() const { return Negated; }
+ void setNegated(bool negated = true) { Negated = negated; }
+
+ void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
+ bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const override;
+
+ void visitUsedExpr(MCStreamer &streamer) const override;
+
+ MCFragment *findAssociatedFragment() const override {
+ return getSubExpr()->findAssociatedFragment();
+ }
+
+ void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {}
+
+ static bool classof(const MCExpr *E) {
+ return E->getKind() == MCExpr::Target;
+ }
+
+public:
+ static VariantKind getKindByName(StringRef Name);
+
+private:
+ int64_t evaluateAsInt64(int64_t Value) const;
+
+ const VariantKind Kind;
+ const MCExpr *SubExpr;
+ bool Negated;
+
+private:
+ explicit AVRMCExpr(VariantKind Kind, const MCExpr *Expr, bool Negated)
+ : Kind(Kind), SubExpr(Expr), Negated(Negated) {}
+ ~AVRMCExpr() {}
+};
+
+} // end namespace llvm
+
+#endif // LLVM_AVR_MCEXPR_H
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.cpp b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.cpp
new file mode 100644
index 0000000..a4fa5c0
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.cpp
@@ -0,0 +1,121 @@
+//===-- AVRMCTargetDesc.cpp - AVR Target Descriptions ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides AVR specific target descriptions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVRELFStreamer.h"
+#include "AVRMCAsmInfo.h"
+#include "AVRMCTargetDesc.h"
+#include "AVRTargetStreamer.h"
+#include "InstPrinter/AVRInstPrinter.h"
+
+#include "llvm/MC/MCELFStreamer.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/TargetRegistry.h"
+
+#define GET_INSTRINFO_MC_DESC
+#include "AVRGenInstrInfo.inc"
+
+#define GET_SUBTARGETINFO_MC_DESC
+#include "AVRGenSubtargetInfo.inc"
+
+#define GET_REGINFO_MC_DESC
+#include "AVRGenRegisterInfo.inc"
+
+using namespace llvm;
+
+static MCInstrInfo *createAVRMCInstrInfo() {
+ MCInstrInfo *X = new MCInstrInfo();
+ InitAVRMCInstrInfo(X);
+
+ return X;
+}
+
+static MCRegisterInfo *createAVRMCRegisterInfo(const Triple &TT) {
+ MCRegisterInfo *X = new MCRegisterInfo();
+ InitAVRMCRegisterInfo(X, 0);
+
+ return X;
+}
+
+static MCSubtargetInfo *createAVRMCSubtargetInfo(const Triple &TT,
+ StringRef CPU, StringRef FS) {
+ return createAVRMCSubtargetInfoImpl(TT, CPU, FS);
+}
+
+static MCInstPrinter *createAVRMCInstPrinter(const Triple &T,
+ unsigned SyntaxVariant,
+ const MCAsmInfo &MAI,
+ const MCInstrInfo &MII,
+ const MCRegisterInfo &MRI) {
+ if (SyntaxVariant == 0) {
+ return new AVRInstPrinter(MAI, MII, MRI);
+ }
+
+ return nullptr;
+}
+
+static MCStreamer *createMCStreamer(const Triple &T, MCContext &Context,
+ MCAsmBackend &MAB, raw_pwrite_stream &OS,
+ MCCodeEmitter *Emitter, bool RelaxAll) {
+ return createELFStreamer(Context, MAB, OS, Emitter, RelaxAll);
+}
+
+static MCTargetStreamer *
+createAVRObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
+ return new AVRELFStreamer(S, STI);
+}
+
+static MCTargetStreamer *createMCAsmTargetStreamer(MCStreamer &S,
+ formatted_raw_ostream &OS,
+ MCInstPrinter *InstPrint,
+ bool isVerboseAsm) {
+ return new AVRTargetAsmStreamer(S);
+}
+
+extern "C" void LLVMInitializeAVRTargetMC() {
+ // Register the MC asm info.
+ RegisterMCAsmInfo<AVRMCAsmInfo> X(getTheAVRTarget());
+
+ // Register the MC instruction info.
+ TargetRegistry::RegisterMCInstrInfo(getTheAVRTarget(), createAVRMCInstrInfo);
+
+ // Register the MC register info.
+ TargetRegistry::RegisterMCRegInfo(getTheAVRTarget(), createAVRMCRegisterInfo);
+
+ // Register the MC subtarget info.
+ TargetRegistry::RegisterMCSubtargetInfo(getTheAVRTarget(),
+ createAVRMCSubtargetInfo);
+
+ // Register the MCInstPrinter.
+ TargetRegistry::RegisterMCInstPrinter(getTheAVRTarget(),
+ createAVRMCInstPrinter);
+
+ // Register the MC Code Emitter
+ TargetRegistry::RegisterMCCodeEmitter(getTheAVRTarget(), createAVRMCCodeEmitter);
+
+ // Register the ELF streamer
+ TargetRegistry::RegisterELFStreamer(getTheAVRTarget(), createMCStreamer);
+
+ // Register the obj target streamer.
+ TargetRegistry::RegisterObjectTargetStreamer(getTheAVRTarget(),
+ createAVRObjectTargetStreamer);
+
+ // Register the asm target streamer.
+ TargetRegistry::RegisterAsmTargetStreamer(getTheAVRTarget(),
+ createMCAsmTargetStreamer);
+
+ // Register the asm backend (as little endian).
+ TargetRegistry::RegisterMCAsmBackend(getTheAVRTarget(), createAVRAsmBackend);
+}
+
diff --git a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h
index b72793d..41a5747 100644
--- a/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h
+++ b/contrib/llvm/lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h
@@ -24,12 +24,13 @@ class MCContext;
class MCInstrInfo;
class MCObjectWriter;
class MCRegisterInfo;
+class MCTargetOptions;
class StringRef;
class Target;
class Triple;
class raw_pwrite_stream;
-extern Target TheAVRTarget;
+Target &getTheAVRTarget();
/// Creates a machine code emitter for AVR.
MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII,
@@ -38,7 +39,8 @@ MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII,
/// Creates an assembly backend for AVR.
MCAsmBackend *createAVRAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU);
+ const Triple &TT, StringRef CPU,
+ const llvm::MCTargetOptions &TO);
/// Creates an ELF object writer for AVR.
MCObjectWriter *createAVRELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI);
diff --git a/contrib/llvm/lib/Target/AVR/README.md b/contrib/llvm/lib/Target/AVR/README.md
new file mode 100644
index 0000000..bd8b453
--- /dev/null
+++ b/contrib/llvm/lib/Target/AVR/README.md
@@ -0,0 +1,8 @@
+# AVR backend
+
+This experimental backend is for the 8-bit Atmel [AVR](https://en.wikipedia.org/wiki/Atmel_AVR) microcontroller.
+
+## Useful links
+
+* [Unresolved bugs](https://llvm.org/bugs/buglist.cgi?product=libraries&component=Backend%3A%20AVR&resolution=---&list_id=109466)
+* [Architecture notes](https://github.com/avr-llvm/architecture)
diff --git a/contrib/llvm/lib/Target/AVR/TargetInfo/AVRTargetInfo.cpp b/contrib/llvm/lib/Target/AVR/TargetInfo/AVRTargetInfo.cpp
index c0e0d20..36cecaa 100644
--- a/contrib/llvm/lib/Target/AVR/TargetInfo/AVRTargetInfo.cpp
+++ b/contrib/llvm/lib/Target/AVR/TargetInfo/AVRTargetInfo.cpp
@@ -9,17 +9,15 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/TargetRegistry.h"
-
namespace llvm {
-Target TheAVRTarget;
+Target &getTheAVRTarget() {
+ static Target TheAVRTarget;
+ return TheAVRTarget;
+}
}
extern "C" void LLVMInitializeAVRTargetInfo() {
- llvm::RegisterTarget<llvm::Triple::avr> X(
- llvm::TheAVRTarget, "avr", "Atmel AVR Microcontroller");
+ llvm::RegisterTarget<llvm::Triple::avr> X(llvm::getTheAVRTarget(), "avr",
+ "Atmel AVR Microcontroller");
}
-// FIXME: Temporary stub - this function must be defined for linking
-// to succeed. Remove once this function is properly implemented.
-extern "C" void LLVMInitializeAVRTargetMC() {
-}
OpenPOWER on IntegriCloud