diff --git a/clang/lib/Basic/Targets/AVR.cpp b/clang/lib/Basic/Targets/AVR.cpp index 3d662cc3ba74f3..5c75bae2d81212 100644 --- a/clang/lib/Basic/Targets/AVR.cpp +++ b/clang/lib/Basic/Targets/AVR.cpp @@ -428,6 +428,23 @@ bool AVRTargetInfo::setCPU(const std::string &Name) { return false; } +std::optional +AVRTargetInfo::handleAsmEscapedChar(char EscChar) const { + switch (EscChar) { + // "%~" represents for 'r' depends on the device has long jump/call. + case '~': + return ArchHasJMPCALL(Arch) ? std::string("") : std::string(1, 'r'); + + // "%!" represents for 'e' depends on the PC register size. + case '!': + return ArchHas3BytePC(Arch) ? std::string(1, 'e') : std::string(""); + + // This is an invalid escape character for AVR. + default: + return std::nullopt; + } +} + void AVRTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { Builder.defineMacro("AVR"); diff --git a/clang/lib/Basic/Targets/AVR.h b/clang/lib/Basic/Targets/AVR.h index 934a01cd621735..e5d683a27c6d56 100644 --- a/clang/lib/Basic/Targets/AVR.h +++ b/clang/lib/Basic/Targets/AVR.h @@ -170,6 +170,7 @@ class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo { bool isValidCPUName(StringRef Name) const override; void fillValidCPUList(SmallVectorImpl &Values) const override; bool setCPU(const std::string &Name) override; + std::optional handleAsmEscapedChar(char EscChar) const override; StringRef getABI() const override { return ABI; } protected: diff --git a/clang/test/CodeGen/avr/avr-inline-asm-constraints.c b/clang/test/CodeGen/avr/avr-inline-asm-constraints.c index c659953ca62478..96774861feb228 100644 --- a/clang/test/CodeGen/avr/avr-inline-asm-constraints.c +++ b/clang/test/CodeGen/avr/avr-inline-asm-constraints.c @@ -1,5 +1,10 @@ // REQUIRES: avr-registered-target -// RUN: %clang_cc1 -triple avr-unknown-unknown -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -x c -triple avr -target-cpu at90s8515 -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes=CHECK,AVR25 %s +// RUN: %clang_cc1 -x c -triple avr -target-cpu atmega328 -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes=CHECK,AVR51 %s +// RUN: %clang_cc1 -x c -triple avr -target-cpu atmega2560 -emit-llvm -o - %s \ +// RUN: | FileCheck --check-prefixes=CHECK,AVR6 %s int data; @@ -122,3 +127,23 @@ void ora() { // CHECK: call addrspace(0) i16 asm "subi r30, $0", "=ra"() asm("subi r30, %0" : "=ra"(data)); } + +void escapeChar(void) { + asm("_foo:"); + // AVR25: call addrspace(0) void asm sideeffect "rcall _foo" + // AVR51: call addrspace(0) void asm sideeffect "call _foo" + // AVR6: call addrspace(0) void asm sideeffect "call _foo" + asm("%~call _foo" ::); + // AVR25: call addrspace(0) void asm sideeffect "rjmp _foo" + // AVR51: call addrspace(0) void asm sideeffect "jmp _foo" + // AVR6: call addrspace(0) void asm sideeffect "jmp _foo" + asm("%~jmp _foo" ::); + // AVR25: call addrspace(0) void asm sideeffect "icall" + // AVR51: call addrspace(0) void asm sideeffect "icall" + // AVR6: call addrspace(0) void asm sideeffect "eicall" + asm("%!icall" ::); + // AVR25: call addrspace(0) void asm sideeffect "ijmp" + // AVR51: call addrspace(0) void asm sideeffect "ijmp" + // AVR6: call addrspace(0) void asm sideeffect "eijmp" + asm("%!ijmp" ::); +}