Skip to content

Treat ';' and '\n' as assembly instruction separators in collectAsmInstrs #149365

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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. Treats '\n' as instruction separator, but not
/// ';' (due to conflict with MachO comment).
/// 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
26 changes: 16 additions & 10 deletions llvm/lib/IR/InlineAsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,23 @@ 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);
SmallVector<StringRef> AsmLines;
AsmStr.split(AsmLines, '\n');

SmallVector<StringRef> AsmInstrs;
AsmInstrs.reserve(AsmLines.size());
for (StringRef AsmLine : AsmLines) {
// Trim most general comments. We don't handle comment blocks (/* ... */).
// We also don't handle '@' (ARM) and ';' (MachO) since they have different
// interpretations in different targets and we don't have target info in IR.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's fine to handle the common cases like '#' and '//' right now.

Just as a minor clarification, my understanding is that we do have the target info available in the IR (e.g., the call instruction from which InlineAsm is extracted). #149365 (comment) also mentions this.

To make things simpler and capture this for the future, how about we update the comment to be a TODO?

auto Trimmed = AsmLine.split('#').first.split("//").first.trim();
if (Trimmed.empty())
continue;
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/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 \0A.pushsection other\0A s_nop 2 \0A s_nop 3 \0A.popsection\0A s_nop 4\0A label:\0A", ""()
ret void
}
; CHECK: define void @callee
Expand Down
Loading