[cfe] Support target-specific escaped character in inline asm

GCC allows each target to define a set of non-letter and non-digit
escaped characters for inline assembly that will be replaced by another
string (They call this "punctuation" characters. The existing "%%" and
"%{" -- replaced by '%' and '{' at the end -- can be seen as special
cases shared by all targets).
This patch implements this feature by adding a new hook in `TargetInfo`.

Differential Revision: https://reviews.llvm.org/D103036
This commit is contained in:
Min-Yih Hsu 2021-05-21 15:15:11 -07:00
parent a5a3efa82a
commit 6685a3f3e4
5 changed files with 59 additions and 1 deletions

View File

@ -1091,6 +1091,12 @@ public:
return std::string(1, *Constraint);
}
/// Replace some escaped characters with another string based on
/// target-specific rules
virtual llvm::Optional<std::string> handleAsmEscapedChar(char C) const {
return llvm::None;
}
/// Returns a string of target-specific clobbers, in LLVM format.
virtual const char *getClobbers() const = 0;

View File

@ -646,6 +646,8 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
continue;
}
const TargetInfo &TI = C.getTargetInfo();
// Escaped "%" character in asm string.
if (CurPtr == StrEnd) {
// % at end of string is invalid (no escape).
@ -656,6 +658,11 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
char EscapedChar = *CurPtr++;
switch (EscapedChar) {
default:
// Handle target-specific escaped characters.
if (auto MaybeReplaceStr = TI.handleAsmEscapedChar(EscapedChar)) {
CurStringPiece += *MaybeReplaceStr;
continue;
}
break;
case '%': // %% -> %
case '{': // %{ -> {
@ -688,7 +695,6 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
EscapedChar = *CurPtr++;
}
const TargetInfo &TI = C.getTargetInfo();
const SourceManager &SM = C.getSourceManager();
const LangOptions &LO = C.getLangOpts();

View File

@ -191,6 +191,30 @@ bool M68kTargetInfo::validateAsmConstraint(
return false;
}
llvm::Optional<std::string>
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

View File

@ -47,6 +47,7 @@ public:
std::string convertConstraint(const char *&Constraint) const override;
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const override;
llvm::Optional<std::string> handleAsmEscapedChar(char EscChar) const override;
const char *getClobbers() const override;
BuiltinVaListKind getBuiltinVaListKind() const override;
bool setCPU(const std::string &Name) override;

View File

@ -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" ::);
}