Index: clang/include/clang/Basic/TargetInfo.h =================================================================== --- clang/include/clang/Basic/TargetInfo.h +++ clang/include/clang/Basic/TargetInfo.h @@ -1091,6 +1091,12 @@ return std::string(1, *Constraint); } + // Replace some escaped characters with another string based on + // target-specific rules + virtual llvm::Optional handleAsmEscapedChar(char C) const { + return llvm::None; + } + /// Returns a string of target-specific clobbers, in LLVM format. virtual const char *getClobbers() const = 0; Index: clang/lib/AST/Stmt.cpp =================================================================== --- clang/lib/AST/Stmt.cpp +++ clang/lib/AST/Stmt.cpp @@ -646,6 +646,8 @@ continue; } + const TargetInfo &TI = C.getTargetInfo(); + // Escaped "%" character in asm string. if (CurPtr == StrEnd) { // % at end of string is invalid (no escape). @@ -666,6 +668,11 @@ CurStringPiece += "${:uid}"; continue; } + // Handle target-specific escaped characters + if (auto MaybeReplaceStr = TI.handleAsmEscapedChar(EscapedChar)) { + CurStringPiece += *MaybeReplaceStr; + continue; + } // Otherwise, we have an operand. If we have accumulated a string so far, // add it to the Pieces list. @@ -688,7 +695,6 @@ EscapedChar = *CurPtr++; } - const TargetInfo &TI = C.getTargetInfo(); const SourceManager &SM = C.getSourceManager(); const LangOptions &LO = C.getLangOpts(); Index: clang/lib/Basic/Targets/M68k.h =================================================================== --- clang/lib/Basic/Targets/M68k.h +++ clang/lib/Basic/Targets/M68k.h @@ -47,6 +47,7 @@ std::string convertConstraint(const char *&Constraint) const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override; + llvm::Optional handleAsmEscapedChar(char EscChar) const override; const char *getClobbers() const override; BuiltinVaListKind getBuiltinVaListKind() const override; bool setCPU(const std::string &Name) override; Index: clang/lib/Basic/Targets/M68k.cpp =================================================================== --- clang/lib/Basic/Targets/M68k.cpp +++ clang/lib/Basic/Targets/M68k.cpp @@ -191,6 +191,30 @@ return false; } +llvm::Optional +M68kTargetInfo::handleAsmEscapedChar(char EscChar) const { + char C; + switch (EscChar) { + case '.': + case '#': + C = EscChar; + break; + case '/': + C = '%'; + break; + case '$': + C = 's'; + break; + case '&': + C = 'd'; + break; + default: + return llvm::None; + } + + return std::string(1, C); +} + std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const { if (*Constraint == 'C') // Two-character constraint; add "^" hint for later parsing Index: clang/test/CodeGen/m68k-asm.c =================================================================== --- /dev/null +++ clang/test/CodeGen/m68k-asm.c @@ -0,0 +1,21 @@ +// REQUIRES: m68k-registered-target +// RUN: %clang -target m68k -S %s -o - | FileCheck %s + +// Test special escaped character in inline assembly +void escaped() { + // '.' -> '.' + // CHECK: move.l #66, %d1 + __asm__ ("move%.l #66, %%d1" ::); + // '#' -> '#' + // CHECK: move.l #66, %d1 + __asm__ ("move.l %#66, %%d1" ::); + // '/' -> '%' + // CHECK: move.l #66, %d1 + __asm__ ("move.l #66, %/d1" ::); + // '$' -> 's' + // CHECK: muls %d0, %d1 + __asm__ ("mul%$ %%d0, %%d1" ::); + // '&' -> 'd' + // CHECK: move.l %d0, %d1 + __asm__ ("move.l %%%&0, %%d1" ::); +}