Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion llvm/include/llvm/IR/InlineAsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,12 @@ class InlineAsm final : public Value {

StringRef getAsmString() const { return AsmString; }
StringRef getConstraintString() const { return Constraints; }
LLVM_ABI void collectAsmStrs(SmallVectorImpl<StringRef> &AsmStrs) const;

/// Parses the assembly instruction and returns individual non-empty
/// instructions in a vector. Handles both '\n' and ';' as instruction
/// separators. Trims comments (marked by '#' and "//") and whitespaces from
/// instructions.
LLVM_ABI SmallVector<StringRef> collectAsmInstrs() const;

/// This static method can be used by the parser to check to see if the
/// specified constraint string is legal for the type.
Expand Down
21 changes: 6 additions & 15 deletions llvm/lib/Analysis/InlineCost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -793,33 +793,24 @@ class InlineCostCallAnalyzer final : public CallAnalyzer {
void onInlineAsm(const InlineAsm &Arg) override {
if (!InlineAsmInstrCost)
return;
SmallVector<StringRef, 4> AsmStrs;
Arg.collectAsmStrs(AsmStrs);
int SectionLevel = 0;
int InlineAsmInstrCount = 0;
for (StringRef AsmStr : AsmStrs) {
// Trim whitespaces and comments.
StringRef Trimmed = AsmStr.trim();
size_t hashPos = Trimmed.find('#');
if (hashPos != StringRef::npos)
Trimmed = Trimmed.substr(0, hashPos);
// Ignore comments.
if (Trimmed.empty())
continue;
for (StringRef AsmInstr : Arg.collectAsmInstrs()) {
// Filter out the outlined assembly instructions from the cost by keeping
// track of the section level and only accounting for instrutions at
// section level of zero. Note there will be duplication in outlined
// sections too, but is not accounted in the inlining cost model.
if (Trimmed.starts_with(".pushsection")) {
if (AsmInstr.starts_with(".pushsection")) {
++SectionLevel;
continue;
}
if (Trimmed.starts_with(".popsection")) {
if (AsmInstr.starts_with(".popsection")) {
--SectionLevel;
continue;
}
// Ignore directives and labels.
if (Trimmed.starts_with(".") || Trimmed.contains(":"))
// Labels are free. Note we only exclude labels that are not followed by
// any other instruction.
if (AsmInstr.ends_with(":"))
continue;
if (SectionLevel == 0)
++InlineAsmInstrCount;
Expand Down
5 changes: 2 additions & 3 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10006,8 +10006,7 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call,
}

int OpNo = -1;
SmallVector<StringRef> AsmStrs;
IA->collectAsmStrs(AsmStrs);
SmallVector<StringRef> AsmInstrs = IA->collectAsmInstrs();

// Second pass over the constraints: compute which constraint option to use.
for (SDISelAsmOperandInfo &OpInfo : ConstraintOperands) {
Expand Down Expand Up @@ -10051,7 +10050,7 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call,
// label, so here we don't handle jmp function label now, but we need to
// enhance it (especilly in PIC model) if we meet meaningful requirements.
if (OpInfo.isIndirect && isFunction(OpInfo.CallOperand) &&
TLI.isInlineAsmTargetBranch(AsmStrs, OpNo) &&
TLI.isInlineAsmTargetBranch(AsmInstrs, OpNo) &&
TM.getCodeModel() != CodeModel::Large) {
OpInfo.isIndirect = false;
OpInfo.ConstraintType = TargetLowering::C_Address;
Expand Down
33 changes: 23 additions & 10 deletions llvm/lib/IR/InlineAsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,30 @@ FunctionType *InlineAsm::getFunctionType() const {
return FTy;
}

void InlineAsm::collectAsmStrs(SmallVectorImpl<StringRef> &AsmStrs) const {
SmallVector<StringRef> InlineAsm::collectAsmInstrs() const {
StringRef AsmStr(AsmString);
AsmStrs.clear();

// TODO: 1) Unify delimiter for inline asm, we also meet other delimiters
// for example "\0A", ";".
// 2) Enhance StringRef. Some of the special delimiter ("\0") can't be
// split in StringRef. Also empty StringRef can not call split (will stuck).
if (AsmStr.empty())
return;
AsmStr.split(AsmStrs, "\n\t", -1, false);
// First break the assembly string into lines.
SmallVector<StringRef> AsmLines;
AsmStr.split(AsmLines, '\n');

SmallVector<StringRef> AsmInstrs;
AsmInstrs.reserve(AsmLines.size());
for (StringRef &AsmLine : AsmLines) {
// First remove the comments. Note it's important to do this before breaking
// by ';' since the comment portion may include that character too.
AsmLine = AsmLine.split('#').first.split("//").first;
if (AsmLine.empty())
continue;
// Break by ';' to collect separate instructions in a single line.
SmallVector<StringRef, 1> CurrentLineAsmInstrs;
AsmLine.split(CurrentLineAsmInstrs, ';');
for (StringRef S : CurrentLineAsmInstrs) {
StringRef Trimmed = S.trim();
if (!Trimmed.empty())
AsmInstrs.push_back(Trimmed);
}
}
return AsmInstrs;
}

/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/X86/inline-asm-function-call-pic.ll
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ define void @func() local_unnamed_addr #0 {
entry:
%call = tail call i32 @static_func()
;; We test call, CALL, and jmp.
tail call void asm sideeffect inteldialect "call ${0:P}\0A\09CALL ${1:P}\0A\09jmp ${1:P}\0A\09shr eax, $$0\0A\09shr ebx, $$0\0A\09shr ecx, $$0\0A\09shr edx, $$0\0A\09shr edi, $$0\0A\09shr esi, $$0\0A\09shr ebp, $$0\0A\09shr esp, $$0", "*m,*m,~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{flags},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"(ptr nonnull elementtype(i32 (...)) @static_func, ptr nonnull elementtype(i32 (...)) @extern_func) #0
tail call void asm sideeffect inteldialect "call ${0:P}\0A\09CALL ${1:P}; jmp ${1:P}\0A\09shr eax, $$0\0Ashr ebx, $$0\0A\09shr ecx, $$0\0A\09shr edx, $$0; shr edi, $$0\0A\09shr esi, $$0\0A\09shr ebp, $$0\0A\09shr esp, $$0", "*m,*m,~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{flags},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"(ptr nonnull elementtype(i32 (...)) @static_func, ptr nonnull elementtype(i32 (...)) @extern_func) #0
ret void
}

Expand Down
5 changes: 2 additions & 3 deletions llvm/test/CodeGen/X86/inline-asm-p-constraint.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ define ptr @foo(ptr %Ptr) {
%Ptr.addr = alloca ptr, align 8
store ptr %Ptr, ptr %Ptr.addr, align 8
; CHECK: movq %rdi, -8(%rsp)
%1 = tail call ptr asm "mov $1, $0\0A\09lea $2, $0", "=r,p,*m,~{dirflag},~{fpsr},~{flags}"(ptr %Ptr, ptr elementtype(ptr) %Ptr.addr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How will \0A\09 get handled by the updated implementation of collectAsmInstrs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

\0A is the newline character and \09 is tab. So the tab will be trimmed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The \0A\09 is in the original test case so it'd be good to keep them for test coverage.

To test new cases (; or # some comment in llvm/test/Transforms/Inline/inline-call-with-asm-call.ll), what do you think of adding new functions instead of changing existing ones in place?

Copy link
Contributor Author

@rlavaee rlavaee Jul 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted the old tests. Just added a single comment in the inlining test.

%1 = tail call ptr asm "mov $1, $0; lea $2, $0", "=r,p,*m,~{dirflag},~{fpsr},~{flags}"(ptr %Ptr, ptr elementtype(ptr) %Ptr.addr)
; CHECK-NEXT: #APP
; CHECK-NEXT: mov (%rdi), %rax
; CHECK-NEXT: lea -8(%rsp), %rax
; CHECK-NEXT: mov (%rdi), %rax; lea -8(%rsp), %rax
; CHECK-NEXT: #NO_APP
ret ptr %1
; CHECK-NEXT: retq
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Transforms/Inline/inline-call-with-asm-call.ll
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ define void @caller(i32 %a, i1 %b) #0 {
;; destination section and two assembly instructions in the outlined "other"
;; section.
define void @callee(i32 %a, i1 %b) {
call void asm sideeffect "s_nop 1\0A\09.pushsection other\0A\09s_nop 2\0A\09s_nop 3\0A\09.popsection\0A\09s_nop 4\0A\09.align 32", ""()
call void asm sideeffect "s_nop 1 # some comment ; still comment \09.pushsection other; s_nop 2 \0A s_nop 3 \0A.popsection\0A s_nop 4; label:\0A", ""()
ret void
}
; CHECK: define void @callee
Expand Down
Loading