diff --git a/llvm/lib/Target/AVR/AVRInstrFormats.td b/llvm/lib/Target/AVR/AVRInstrFormats.td --- a/llvm/lib/Target/AVR/AVRInstrFormats.td +++ b/llvm/lib/Target/AVR/AVRInstrFormats.td @@ -502,6 +502,29 @@ let Inst{15 - 0} = k; } +//===---------------------------------------------------------------------===// +// Special format for the LDS/STS instructions on AVRTiny. +// <|1010|ikkk|dddd|kkkk> +// d = R16 ~ R31 +// i = 0 - lds, 1 - sts +// k = 7-bit data space address +//===---------------------------------------------------------------------===// +class FLDSSTSTINY pattern> + : AVRInst16 { + bits<5> rd; + bits<7> k; + + let Inst{15 - 12} = 0b1010; + + let Inst{11} = i; + + let Inst{10 - 8} = k{6 - 4}; + let Inst{7 - 4} = rd{3 - 0}; + let Inst{3 - 0} = k{3 - 0}; + + let DecoderNamespace = "AVRTiny"; +} + // <|1001|0100|bfff|1000> class FS pattern> : AVRInst16 { diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td --- a/llvm/lib/Target/AVR/AVRInstrInfo.td +++ b/llvm/lib/Target/AVR/AVRInstrInfo.td @@ -212,6 +212,11 @@ // A 16-bit address (which can lead to an R_AVR_16 relocation). def imm16 : Operand { let EncoderMethod = "encodeImm"; } +// A 7-bit address (which can lead to an R_AVR_LDS_STS_16 relocation). +def imm7tiny : Operand { + let EncoderMethod = "encodeImm"; +} + /// A 6-bit immediate used in the ADIW/SBIW instructions. def imm_arith6 : Operand { let EncoderMethod = "encodeImm"; @@ -321,7 +326,7 @@ AssemblerPredicate<(all_of FeatureTinyEncoding)>; def HasNonTinyEncoding : Predicate<"!Subtarget->hasTinyEncoding()">, - AssemblerPredicate<(all_of (not FeatureTinyEncoding))>; + AssemblerPredicate<(any_of (not FeatureTinyEncoding))>; // AVR specific condition code. These correspond to AVR_*_COND in // AVRInstrInfo.td. They must be kept in synch. @@ -1288,6 +1293,11 @@ : $k))]>, Requires<[HasSRAM, HasNonTinyEncoding]>; + // Load from data space into register, which is only available on AVRTiny. + def LDSRdKTiny : FLDSSTSTINY<0b0, (outs LD8:$rd), (ins imm7tiny:$k), + "lds\t$rd, $k", []>, + Requires<[HasSRAM, HasTinyEncoding]>; + // LDSW Rd+1:Rd, K+1:K // // Expands to: @@ -1506,6 +1516,11 @@ : $k)]>, Requires<[HasSRAM, HasNonTinyEncoding]>; +// Store from register to data space, which is only available on AVRTiny. +def STSKRrTiny : FLDSSTSTINY<0b1, (outs), (ins imm7tiny:$k, LD8:$rd), + "sts\t$k, $rd", []>, + Requires<[HasSRAM, HasTinyEncoding]>; + // STSW K+1:K, Rr+1:Rr // // Expands to: diff --git a/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp b/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp --- a/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp +++ b/llvm/lib/Target/AVR/Disassembler/AVRDisassembler.cpp @@ -425,6 +425,14 @@ if (Result == MCDisassembler::Fail) return MCDisassembler::Fail; + // Try to decode AVRTiny instructions. + if (STI.getFeatureBits()[AVR::FeatureTinyEncoding]) { + Result = decodeInstruction(DecoderTableAVRTiny16, Instr, Insn, Address, + this, STI); + if (Result != MCDisassembler::Fail) + return Result; + } + // Try to auto-decode a 16-bit instruction. Result = decodeInstruction(getDecoderTable(Size), Instr, Insn, Address, this, STI); diff --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp b/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp --- a/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp +++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp @@ -187,6 +187,16 @@ Value = ((Value & 0x30) << 5) | (Value & 0x0f); } +/// 7-bit data space address fixup for the LDS/STS instructions on AVRTiny. +/// +/// Resolves to: +/// 1010 ikkk dddd kkkk +static void fixup_lds_sts_16(const MCFixup &Fixup, uint64_t &Value, + MCContext *Ctx = nullptr) { + unsigned_width(7, Value, std::string("immediate"), Fixup, Ctx); + Value = ((Value & 0x70) << 8) | (Value & 0x0f); +} + /// Adjusts a program memory address. /// This is a simple right-shift. static void pm(uint64_t &Value) { Value >>= 1; } @@ -343,6 +353,10 @@ adjust::fixup_port6(Fixup, Value, Ctx); break; + case AVR::fixup_lds_sts_16: + adjust::fixup_lds_sts_16(Fixup, Value, Ctx); + break; + // Fixups which do not require adjustments. case FK_Data_1: case FK_Data_2: diff --git a/llvm/test/MC/AVR/inst-lds-tiny.s b/llvm/test/MC/AVR/inst-lds-tiny.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/AVR/inst-lds-tiny.s @@ -0,0 +1,23 @@ +; RUN: llvm-mc -triple avr -mattr=sram,tinyencoding -show-encoding < %s | FileCheck %s +; RUN: llvm-mc -filetype=obj -triple avr -mattr=sram,tinyencoding < %s | llvm-objdump --no-print-imm-hex -dr --mattr=sram,tinyencoding - | FileCheck -check-prefix=CHECK-INST %s + +foo: + lds r16, 113 + lds r29, 62 + lds r22, 44 + lds r27, 92 + lds r20, SYMBOL+12 + +; CHECK: lds r16, 113 ; encoding: [0x01,0xa7] +; CHECK: lds r29, 62 ; encoding: [0xde,0xa3] +; CHECK: lds r22, 44 ; encoding: [0x6c,0xa2] +; CHECK: lds r27, 92 ; encoding: [0xbc,0xa5] +; CHECK: lds r20, SYMBOL+12 ; encoding: [0x40'A',0xa0'A'] +; CHECK: ; fixup A - offset: 0, value: SYMBOL+12, kind: fixup_lds_sts_16 + +; CHECK-INST: lds r16, 113 +; CHECK-INST: lds r29, 62 +; CHECK-INST: lds r22, 44 +; CHECK-INST: lds r27, 92 +; CHECK-INST: lds r20, 0 +; CHECK-INST: R_AVR_LDS_STS_16 SYMBOL+0xc diff --git a/llvm/test/MC/AVR/inst-sts-tiny.s b/llvm/test/MC/AVR/inst-sts-tiny.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/AVR/inst-sts-tiny.s @@ -0,0 +1,17 @@ +; RUN: llvm-mc -triple avr -mattr=sram,tinyencoding -show-encoding < %s | FileCheck %s +; RUN: llvm-mc -filetype=obj -triple avr -mattr=sram,tinyencoding < %s | llvm-objdump --no-print-imm-hex -dr --mattr=sram,tinyencoding - | FileCheck -check-prefix=CHECK-INST %s + +foo: + sts 3, r16 + sts 127, r17 + sts SYMBOL+1, r25 + +; CHECK: sts 3, r16 ; encoding: [0x03,0xa8] +; CHECK: sts 127, r17 ; encoding: [0x1f,0xaf] +; CHECK: sts SYMBOL+1, r25 ; encoding: [0x90'A',0xa8'A'] +; CHECK: ; fixup A - offset: 0, value: SYMBOL+1, kind: fixup_lds_sts_16 + +; CHECK-INST: sts 3, r16 +; CHECK-INST: sts 127, r17 +; CHECK-INST: sts 0, r25 +; CHECK-INST: R_AVR_LDS_STS_16 SYMBOL+0x1