[AsmPrinter] refactor to support %c w/ GlobalAddress'

Summary:
Targets like ARM, MSP430, PPC, and SystemZ have complex behavior when
printing the address of a MachineOperand::MO_GlobalAddress. Move that
handling into a new overriden method in each base class. A virtual
method was added to the base class for handling the generic case.

Refactors a few subclasses to support the target independent %a, %c, and
%n.

The patch also contains small cleanups for AVRAsmPrinter and
SystemZAsmPrinter.

It seems that NVPTXTargetLowering is possibly missing some logic to
transform GlobalAddressSDNodes for
TargetLowering::LowerAsmOperandForConstraint to handle with "i" extended
inline assembly asm constraints.

Fixes:
- https://bugs.llvm.org/show_bug.cgi?id=41402
- https://github.com/ClangBuiltLinux/linux/issues/449

Reviewers: echristo, void

Reviewed By: void

Subscribers: void, craig.topper, jholewinski, dschuff, jyknight, dylanmckay, sdardis, nemanjai, javed.absar, sbc100, jgravelle-google, eraman, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, jrtc27, atanasyan, jsji, llvm-commits, kees, tpimh, nathanchance, peter.smith, srhines

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D60887

llvm-svn: 359337
This commit is contained in:
Nick Desaulniers 2019-04-26 18:45:04 +00:00
parent 74967cb4e0
commit 7ab164c4a4
33 changed files with 408 additions and 88 deletions

View File

@ -590,6 +590,10 @@ public:
virtual void PrintSpecial(const MachineInstr *MI, raw_ostream &OS, virtual void PrintSpecial(const MachineInstr *MI, raw_ostream &OS,
const char *Code) const; const char *Code) const;
/// Print the MachineOperand as a symbol. Targets with complex handling of
/// symbol references should override the base implementation.
virtual void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS);
/// Print the specified operand of MI, an INLINEASM instruction, using the /// Print the specified operand of MI, an INLINEASM instruction, using the
/// specified assembler variant. Targets should override this to format as /// specified assembler variant. Targets should override this to format as
/// appropriate. This method can return true if the operand is erroneous. /// appropriate. This method can return true if the operand is erroneous.

View File

@ -599,6 +599,12 @@ void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS,
} }
} }
void AsmPrinter::PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS) {
assert(MO.isGlobal() && "caller should check MO.isGlobal");
getSymbol(MO.getGlobal())->print(OS, MAI);
printOffset(MO.getOffset(), OS);
}
/// PrintAsmOperand - Print the specified operand of MI, an INLINEASM /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM
/// instruction, using the specified assembler variant. Targets should /// instruction, using the specified assembler variant. Targets should
/// override this to format as appropriate for machine specific ExtraCodes /// override this to format as appropriate for machine specific ExtraCodes
@ -621,10 +627,15 @@ bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
} }
LLVM_FALLTHROUGH; // GCC allows '%a' to behave like '%c' with immediates. LLVM_FALLTHROUGH; // GCC allows '%a' to behave like '%c' with immediates.
case 'c': // Substitute immediate value without immediate syntax case 'c': // Substitute immediate value without immediate syntax
if (!MO.isImm()) if (MO.isImm()) {
return true; O << MO.getImm();
O << MO.getImm(); return false;
return false; }
if (MO.isGlobal()) {
PrintSymbolOperand(MO, O);
return false;
}
return true;
case 'n': // Negate the immediate constant. case 'n': // Negate the immediate constant.
if (!MO.isImm()) if (!MO.isImm())
return true; return true;

View File

@ -436,14 +436,7 @@ void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum,
break; break;
} }
case MachineOperand::MO_GlobalAddress: { case MachineOperand::MO_GlobalAddress: {
const GlobalValue *GV = MO.getGlobal(); PrintSymbolOperand(MO, O);
MCSymbol *Sym = getSymbol(GV);
// FIXME: Can we get anything other than a plain symbol here?
assert(!MO.getTargetFlags() && "Unknown operand target flag!");
Sym->print(O, MAI);
printOffset(MO.getOffset(), O);
break; break;
} }
case MachineOperand::MO_BlockAddress: { case MachineOperand::MO_BlockAddress: {

View File

@ -183,10 +183,21 @@ bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
return false; return false;
} }
void ARMAsmPrinter::PrintSymbolOperand(const MachineOperand &MO,
raw_ostream &O) {
assert(MO.isGlobal() && "caller should check MO.isGlobal");
unsigned TF = MO.getTargetFlags();
if (TF & ARMII::MO_LO16)
O << ":lower16:";
else if (TF & ARMII::MO_HI16)
O << ":upper16:";
GetARMGVSymbol(MO.getGlobal(), TF)->print(O, MAI);
printOffset(MO.getOffset(), O);
}
void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
raw_ostream &O) { raw_ostream &O) {
const MachineOperand &MO = MI->getOperand(OpNum); const MachineOperand &MO = MI->getOperand(OpNum);
unsigned TF = MO.getTargetFlags();
switch (MO.getType()) { switch (MO.getType()) {
default: llvm_unreachable("<unknown operand type>"); default: llvm_unreachable("<unknown operand type>");
@ -203,27 +214,20 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
break; break;
} }
case MachineOperand::MO_Immediate: { case MachineOperand::MO_Immediate: {
int64_t Imm = MO.getImm();
O << '#'; O << '#';
unsigned TF = MO.getTargetFlags();
if (TF == ARMII::MO_LO16) if (TF == ARMII::MO_LO16)
O << ":lower16:"; O << ":lower16:";
else if (TF == ARMII::MO_HI16) else if (TF == ARMII::MO_HI16)
O << ":upper16:"; O << ":upper16:";
O << Imm; O << MO.getImm();
break; break;
} }
case MachineOperand::MO_MachineBasicBlock: case MachineOperand::MO_MachineBasicBlock:
MO.getMBB()->getSymbol()->print(O, MAI); MO.getMBB()->getSymbol()->print(O, MAI);
return; return;
case MachineOperand::MO_GlobalAddress: { case MachineOperand::MO_GlobalAddress: {
const GlobalValue *GV = MO.getGlobal(); PrintSymbolOperand(MO, O);
if (TF & ARMII::MO_LO16)
O << ":lower16:";
else if (TF & ARMII::MO_HI16)
O << ":upper16:";
GetARMGVSymbol(GV, TF)->print(O, MAI);
printOffset(MO.getOffset(), O);
break; break;
} }
case MachineOperand::MO_ConstantPoolIndex: case MachineOperand::MO_ConstantPoolIndex:

View File

@ -75,6 +75,7 @@ public:
void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);
void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O) override;
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
const char *ExtraCode, raw_ostream &O) override; const char *ExtraCode, raw_ostream &O) override;
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,

View File

@ -42,8 +42,7 @@ public:
StringRef getPassName() const override { return "AVR Assembly Printer"; } StringRef getPassName() const override { return "AVR Assembly Printer"; }
void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O, void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O);
const char *Modifier = 0);
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
const char *ExtraCode, raw_ostream &O) override; const char *ExtraCode, raw_ostream &O) override;
@ -58,7 +57,7 @@ private:
}; };
void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O, const char *Modifier) { raw_ostream &O) {
const MachineOperand &MO = MI->getOperand(OpNo); const MachineOperand &MO = MI->getOperand(OpNo);
switch (MO.getType()) { switch (MO.getType()) {

View File

@ -104,7 +104,7 @@ void BPFAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
bool BPFAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, bool BPFAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
const char *ExtraCode, raw_ostream &O) { const char *ExtraCode, raw_ostream &O) {
if (ExtraCode && ExtraCode[0]) if (ExtraCode && ExtraCode[0])
return true; // BPF does not have special modifiers return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
printOperand(MI, OpNo, O); printOperand(MI, OpNo, O);
return false; return false;

View File

@ -91,9 +91,7 @@ void HexagonAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
GetCPISymbol(MO.getIndex())->print(O, MAI); GetCPISymbol(MO.getIndex())->print(O, MAI);
return; return;
case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_GlobalAddress:
// Computing the address of a global symbol, not calling it. PrintSymbolOperand(MO, O);
getSymbol(MO.getGlobal())->print(O, MAI);
printOffset(MO.getOffset(), O);
return; return;
} }
} }

View File

@ -136,7 +136,7 @@ bool LanaiAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
return false; return false;
} }
default: default:
return true; // Unknown modifier. return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
} }
} }
printOperand(MI, OpNo, O); printOperand(MI, OpNo, O);

View File

@ -47,6 +47,7 @@ namespace {
bool runOnMachineFunction(MachineFunction &MF) override; bool runOnMachineFunction(MachineFunction &MF) override;
void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O) override;
void printOperand(const MachineInstr *MI, int OpNum, void printOperand(const MachineInstr *MI, int OpNum,
raw_ostream &O, const char* Modifier = nullptr); raw_ostream &O, const char* Modifier = nullptr);
void printSrcMemOperand(const MachineInstr *MI, int OpNum, void printSrcMemOperand(const MachineInstr *MI, int OpNum,
@ -61,6 +62,17 @@ namespace {
}; };
} // end of anonymous namespace } // end of anonymous namespace
void MSP430AsmPrinter::PrintSymbolOperand(const MachineOperand &MO,
raw_ostream &O) {
uint64_t Offset = MO.getOffset();
if (Offset)
O << '(' << Offset << '+';
getSymbol(MO.getGlobal())->print(O, MAI);
if (Offset)
O << ')';
}
void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum, void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
raw_ostream &O, const char *Modifier) { raw_ostream &O, const char *Modifier) {
@ -79,25 +91,13 @@ void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
MO.getMBB()->getSymbol()->print(O, MAI); MO.getMBB()->getSymbol()->print(O, MAI);
return; return;
case MachineOperand::MO_GlobalAddress: { case MachineOperand::MO_GlobalAddress: {
bool isMemOp = Modifier && !strcmp(Modifier, "mem");
uint64_t Offset = MO.getOffset();
// If the global address expression is a part of displacement field with a // If the global address expression is a part of displacement field with a
// register base, we should not emit any prefix symbol here, e.g. // register base, we should not emit any prefix symbol here, e.g.
// mov.w &foo, r1
// vs
// mov.w glb(r1), r2 // mov.w glb(r1), r2
// Otherwise (!) msp430-as will silently miscompile the output :( // Otherwise (!) msp430-as will silently miscompile the output :(
if (!Modifier || strcmp(Modifier, "nohash")) if (!Modifier || strcmp(Modifier, "nohash"))
O << (isMemOp ? '&' : '#'); O << '#';
if (Offset) PrintSymbolOperand(MO, O);
O << '(' << Offset << '+';
getSymbol(MO.getGlobal())->print(O, MAI);
if (Offset)
O << ')';
return; return;
} }
} }
@ -129,7 +129,7 @@ bool MSP430AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
const char *ExtraCode, raw_ostream &O) { const char *ExtraCode, raw_ostream &O) {
// Does this asm operand have a single letter operand modifier? // Does this asm operand have a single letter operand modifier?
if (ExtraCode && ExtraCode[0]) if (ExtraCode && ExtraCode[0])
return true; // Unknown modifier. return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
printOperand(MI, OpNo, O); printOperand(MI, OpNo, O);
return false; return false;

View File

@ -692,7 +692,7 @@ void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
return; return;
case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_GlobalAddress:
getSymbol(MO.getGlobal())->print(O, MAI); PrintSymbolOperand(MO, O);
break; break;
case MachineOperand::MO_BlockAddress: { case MachineOperand::MO_BlockAddress: {

View File

@ -2230,7 +2230,7 @@ void NVPTXAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
break; break;
case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_GlobalAddress:
getSymbol(MO.getGlobal())->print(O, MAI); PrintSymbolOperand(MO, O);
break; break;
case MachineOperand::MO_MachineBasicBlock: case MachineOperand::MO_MachineBasicBlock:

View File

@ -101,6 +101,7 @@ public:
/// The \p MI would be INLINEASM ONLY. /// The \p MI would be INLINEASM ONLY.
void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O); void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O);
void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O) override;
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
const char *ExtraCode, raw_ostream &O) override; const char *ExtraCode, raw_ostream &O) override;
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
@ -158,6 +159,30 @@ public:
} // end anonymous namespace } // end anonymous namespace
void PPCAsmPrinter::PrintSymbolOperand(const MachineOperand &MO,
raw_ostream &O) {
// Computing the address of a global symbol, not calling it.
const GlobalValue *GV = MO.getGlobal();
MCSymbol *SymToPrint;
// External or weakly linked global variables need non-lazily-resolved stubs
if (Subtarget->hasLazyResolverStub(GV)) {
SymToPrint = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");
MachineModuleInfoImpl::StubValueTy &StubSym =
MMI->getObjFileInfo<MachineModuleInfoMachO>().getGVStubEntry(
SymToPrint);
if (!StubSym.getPointer())
StubSym = MachineModuleInfoImpl::StubValueTy(getSymbol(GV),
!GV->hasInternalLinkage());
} else {
SymToPrint = getSymbol(GV);
}
SymToPrint->print(O, MAI);
printOffset(MO.getOffset(), O);
}
void PPCAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, void PPCAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O) { raw_ostream &O) {
const DataLayout &DL = getDataLayout(); const DataLayout &DL = getDataLayout();
@ -190,26 +215,7 @@ void PPCAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
GetBlockAddressSymbol(MO.getBlockAddress())->print(O, MAI); GetBlockAddressSymbol(MO.getBlockAddress())->print(O, MAI);
return; return;
case MachineOperand::MO_GlobalAddress: { case MachineOperand::MO_GlobalAddress: {
// Computing the address of a global symbol, not calling it. PrintSymbolOperand(MO, O);
const GlobalValue *GV = MO.getGlobal();
MCSymbol *SymToPrint;
// External or weakly linked global variables need non-lazily-resolved stubs
if (Subtarget->hasLazyResolverStub(GV)) {
SymToPrint = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");
MachineModuleInfoImpl::StubValueTy &StubSym =
MMI->getObjFileInfo<MachineModuleInfoMachO>().getGVStubEntry(
SymToPrint);
if (!StubSym.getPointer())
StubSym = MachineModuleInfoImpl::StubValueTy(getSymbol(GV),
!GV->hasInternalLinkage());
} else {
SymToPrint = getSymbol(GV);
}
SymToPrint->print(O, MAI);
printOffset(MO.getOffset(), O);
return; return;
} }

View File

@ -357,7 +357,7 @@ void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
MO.getMBB()->getSymbol()->print(O, MAI); MO.getMBB()->getSymbol()->print(O, MAI);
return; return;
case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_GlobalAddress:
getSymbol(MO.getGlobal())->print(O, MAI); PrintSymbolOperand(MO, O);
break; break;
case MachineOperand::MO_BlockAddress: case MachineOperand::MO_BlockAddress:
O << GetBlockAddressSymbol(MO.getBlockAddress())->getName(); O << GetBlockAddressSymbol(MO.getBlockAddress())->getName();

View File

@ -620,15 +620,11 @@ EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) {
bool SystemZAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, bool SystemZAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
const char *ExtraCode, const char *ExtraCode,
raw_ostream &OS) { raw_ostream &OS) {
if (ExtraCode && *ExtraCode == 'n') { if (ExtraCode)
if (!MI->getOperand(OpNo).isImm()) return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS);
return true; SystemZMCInstLower Lower(MF->getContext(), *this);
OS << -int64_t(MI->getOperand(OpNo).getImm()); MCOperand MO(Lower.lowerOperand(MI->getOperand(OpNo)));
} else { SystemZInstPrinter::printOperand(MO, MAI, OS);
SystemZMCInstLower Lower(MF->getContext(), *this);
MCOperand MO(Lower.lowerOperand(MI->getOperand(OpNo)));
SystemZInstPrinter::printOperand(MO, MAI, OS);
}
return false; return false;
} }

View File

@ -407,8 +407,7 @@ bool WebAssemblyAsmPrinter::PrintAsmOperand(const MachineInstr *MI,
OS << regToString(MO); OS << regToString(MO);
return false; return false;
case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_GlobalAddress:
getSymbol(MO.getGlobal())->print(OS, MAI); PrintSymbolOperand(MO, OS);
printOffset(MO.getOffset(), OS);
return false; return false;
case MachineOperand::MO_ExternalSymbol: case MachineOperand::MO_ExternalSymbol:
GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI); GetExternalSymbolSymbol(MO.getSymbolName())->print(OS, MAI);

View File

@ -299,6 +299,7 @@ void X86AsmPrinter::PrintLeaMemReference(const MachineInstr *MI, unsigned OpNo,
case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_GlobalAddress:
case MachineOperand::MO_ConstantPoolIndex: case MachineOperand::MO_ConstantPoolIndex:
PrintSymbolOperand(DispSpec, O); PrintSymbolOperand(DispSpec, O);
break;
} }
if (Modifier && strcmp(Modifier, "H") == 0) if (Modifier && strcmp(Modifier, "H") == 0)

View File

@ -102,7 +102,7 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
// Choose between emitting .seh_ directives and .cv_fpo_ directives. // Choose between emitting .seh_ directives and .cv_fpo_ directives.
void EmitSEHInstruction(const MachineInstr *MI); void EmitSEHInstruction(const MachineInstr *MI);
void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O); void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O) override;
void PrintOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O); void PrintOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O);
void PrintModifiedOperand(const MachineInstr *MI, unsigned OpNo, void PrintModifiedOperand(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O, const char *Modifier); raw_ostream &O, const char *Modifier);

View File

@ -213,7 +213,7 @@ void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
MO.getMBB()->getSymbol()->print(O, MAI); MO.getMBB()->getSymbol()->print(O, MAI);
break; break;
case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_GlobalAddress:
getSymbol(MO.getGlobal())->print(O, MAI); PrintSymbolOperand(MO, O);
break; break;
case MachineOperand::MO_ConstantPoolIndex: case MachineOperand::MO_ConstantPoolIndex:
O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_' O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_'

View File

@ -0,0 +1,27 @@
; RUN: llc -mtriple=aarch64-linux-gnu < %s | FileCheck %s
; Test that %c works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template0
; CHECK: TEST 42
define dso_local i32 @test_inlineasm_c_output_template0() {
tail call void asm sideeffect "//TEST ${0:c}", "i"(i32 42)
ret i32 42
}
; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template1:
; CHECK: TEST {{_?}}baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect "//TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 43
}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: TEST -42
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "//TEST ${0:n}", "i"(i32 42)
ret i32 42
}

View File

@ -8,6 +8,15 @@ define dso_local i32 @test_inlineasm_c_output_template0() {
ret i32 42 ret i32 42
} }
; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: @TEST baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "@TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 42
}
; Test that %n works with immediates ; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template1 ; CHECK-LABEL: test_inlineasm_c_output_template1
; CHECK: @TEST -42 ; CHECK: @TEST -42

View File

@ -0,0 +1,26 @@
; RUN: llc -mtriple=bpfel-linux-gnu < %s | FileCheck %s
; Test that %c works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template0
; CHECK: #TEST 42
define dso_local i32 @test_inlineasm_c_output_template0() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32 42)
ret i32 42
}
; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template1
; CHECK: #TEST baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 42
}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: #TEST -42
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "#TEST ${0:n}", "i"(i32 42)
ret i32 42
}

View File

@ -8,10 +8,19 @@ define dso_local i32 @test_inlineasm_c_output_template0() {
ret i32 42 ret i32 42
} }
; Test that %n works with immediates ; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template1 ; CHECK-LABEL: test_inlineasm_c_output_template1:
; CHECK: //TEST -42 ; CHECK: TEST {{_?}}baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template1() { define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect "//TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 43
}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: //TEST -42
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "//TEST ${0:n}", "i"(i32 42) tail call void asm sideeffect "//TEST ${0:n}", "i"(i32 42)
ret i32 42 ret i32 42
} }

View File

@ -0,0 +1,26 @@
; RUN: llc -mtriple=lanai-linux-gnueabi < %s | FileCheck %s
; Test that %c works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template0
; CHECK: !TEST 42
define dso_local i32 @test_inlineasm_c_output_template0() {
tail call void asm sideeffect "!TEST ${0:c}", "i"(i32 42)
ret i32 42
}
; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template1
; CHECK: !TEST baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect "!TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 42
}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: !TEST -42
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "!TEST ${0:n}", "i"(i32 42)
ret i32 42
}

View File

@ -0,0 +1,26 @@
; RUN: llc -mtriple=msp430-linux-gnu < %s | FileCheck %s
; Test that %c works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template0
; CHECK: ;TEST 42
define dso_local i32 @test_inlineasm_c_output_template0() {
tail call void asm sideeffect ";TEST ${0:c}", "i"(i32 42)
ret i32 42
}
; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: ;TEST baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect ";TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 42
}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template1
; CHECK: ;TEST -42
define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect ";TEST ${0:n}", "i"(i32 42)
ret i32 42
}

View File

@ -0,0 +1,26 @@
; RUN: llc -mtriple=mips64el-linux-gnu < %s | FileCheck %s
; Test that %c works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template0
; CHECK: #TEST 42
define dso_local i32 @test_inlineasm_c_output_template0() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32 42)
ret i32 42
}
; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template1
; CHECK: #TEST baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 42
}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: #TEST -42
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "#TEST ${0:n}", "i"(i32 42)
ret i32 42
}

View File

@ -0,0 +1,28 @@
; RUN: llc -march=nvptx < %s | FileCheck %s
; Test that %c works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template0
; CHECK: //TEST 42
define dso_local i32 @test_inlineasm_c_output_template0() {
tail call void asm sideeffect "//TEST ${0:c}", "i"(i32 42)
ret i32 42
}
; Test that %c works with global address
; FIXME: seems this case isn't handled properly by
; SelectionDAG TargetLowering::LowerAsmOperandForConstraint?
; check: test_inlineasm_c_output_template1
; check: //TEST baz
;@baz = internal global i32 0, align 4
;define dso_local i32 @test_inlineasm_c_output_template1() {
; tail call void asm sideeffect "//TEST ${0:c}", "i"(i32* nonnull @baz)
; ret i32 42
;}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: //TEST -42
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "//TEST ${0:n}", "i"(i32 42)
ret i32 42
}

View File

@ -8,10 +8,19 @@ define dso_local i32 @test_inlineasm_c_output_template0() {
ret i32 42 ret i32 42
} }
; Test that %n works with immediates ; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template1 ; CHECK-LABEL: test_inlineasm_c_output_template1:
; CHECK: #TEST -42 ; CHECK: #TEST baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template1() { define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 43
}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: #TEST -42
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "#TEST ${0:n}", "i"(i32 42) tail call void asm sideeffect "#TEST ${0:n}", "i"(i32 42)
ret i32 42 ret i32 42
} }

View File

@ -0,0 +1,26 @@
; RUN: llc -mtriple=sparc-linux-gnu < %s | FileCheck %s
; Test that %c works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template0
; CHECK: !TEST 42
define dso_local i32 @test_inlineasm_c_output_template0() {
tail call void asm sideeffect "!TEST ${0:c}", "i"(i32 42)
ret i32 42
}
; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template1
; CHECK: !TEST baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect "!TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 42
}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: !TEST -42
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "!TEST ${0:n}", "i"(i32 42)
ret i32 42
}

View File

@ -0,0 +1,26 @@
; RUN: llc -mtriple=s390x-linux-gnu < %s | FileCheck %s
; Test that %c works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template0
; CHECK: #TEST 42
define dso_local i32 @test_inlineasm_c_output_template0() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32 42)
ret i32 42
}
; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: #TEST baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 42
}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template1
; CHECK: #TEST -42
define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect "#TEST ${0:n}", "i"(i32 42)
ret i32 42
}

View File

@ -0,0 +1,26 @@
; RUN: llc -mtriple=wasm32 < %s | FileCheck %s
; Test that %c works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template0
; CHECK: #TEST 42
define dso_local i32 @test_inlineasm_c_output_template0() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32 42)
ret i32 42
}
; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: #TEST baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 42
}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template1
; CHECK: #TEST -42
define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect "#TEST ${0:n}", "i"(i32 42)
ret i32 42
}

View File

@ -0,0 +1,18 @@
; RUN: llc -mtriple=x86_64-linux-gnu < %s | FileCheck %s
; Test that %c works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template0
; CHECK: #TEST 42
define dso_local i32 @test_inlineasm_c_output_template0() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32 42)
ret i32 42
}
; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template1
; CHECK: #TEST baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 42
}

View File

@ -0,0 +1,26 @@
; RUN: llc -march=xcore < %s | FileCheck %s
; Test that %c works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template0
; CHECK: #TEST 42
define dso_local i32 @test_inlineasm_c_output_template0() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32 42)
ret i32 42
}
; Test that %c works with global address
; CHECK-LABEL: test_inlineasm_c_output_template2
; CHECK: #TEST baz
@baz = internal global i32 0, align 4
define dso_local i32 @test_inlineasm_c_output_template2() {
tail call void asm sideeffect "#TEST ${0:c}", "i"(i32* nonnull @baz)
ret i32 42
}
; Test that %n works with immediates
; CHECK-LABEL: test_inlineasm_c_output_template1
; CHECK: #TEST -42
define dso_local i32 @test_inlineasm_c_output_template1() {
tail call void asm sideeffect "#TEST ${0:n}", "i"(i32 42)
ret i32 42
}