.addReg(V2);
}
-// Insert instructions to initialize the Mips16 SP Alias register in the
-// first MBB of the function.
-//
-void Mips16DAGToDAGISel::initMips16SPAliasReg(MachineFunction &MF) {
- MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
-
- if (!MipsFI->mips16SPAliasRegSet())
- return;
-
- MachineBasicBlock &MBB = MF.front();
- MachineBasicBlock::iterator I = MBB.begin();
- const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
- DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc();
- unsigned Mips16SPAliasReg = MipsFI->getMips16SPAliasReg();
-
- BuildMI(MBB, I, DL, TII.get(Mips::MoveR3216), Mips16SPAliasReg)
- .addReg(Mips::SP);
-}
-
void Mips16DAGToDAGISel::processFunctionAfterISel(MachineFunction &MF) {
initGlobalBaseReg(MF);
- initMips16SPAliasReg(MF);
}
-/// getMips16SPAliasReg - Output the instructions required to put the
-/// SP into a Mips16 accessible aliased register.
-SDValue Mips16DAGToDAGISel::getMips16SPAliasReg() {
- unsigned Mips16SPAliasReg =
- MF->getInfo<MipsFunctionInfo>()->getMips16SPAliasReg();
- auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
- return CurDAG->getRegister(Mips16SPAliasReg, PtrVT);
-}
-
-void Mips16DAGToDAGISel::getMips16SPRefReg(SDNode *Parent, SDValue &AliasReg) {
- auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
- SDValue AliasFPReg = CurDAG->getRegister(Mips::S0, PtrVT);
- if (Parent) {
- switch (Parent->getOpcode()) {
- case ISD::LOAD: {
- LoadSDNode *SD = dyn_cast<LoadSDNode>(Parent);
- switch (SD->getMemoryVT().getSizeInBits()) {
- case 8:
- case 16:
- AliasReg = Subtarget->getFrameLowering()->hasFP(*MF)
- ? AliasFPReg
- : getMips16SPAliasReg();
- return;
- }
- break;
- }
- case ISD::STORE: {
- StoreSDNode *SD = dyn_cast<StoreSDNode>(Parent);
- switch (SD->getMemoryVT().getSizeInBits()) {
- case 8:
- case 16:
- AliasReg = Subtarget->getFrameLowering()->hasFP(*MF)
- ? AliasFPReg
- : getMips16SPAliasReg();
- return;
- }
- break;
- }
- }
- }
- AliasReg = CurDAG->getRegister(Mips::SP, PtrVT);
- return;
-}
-
-bool Mips16DAGToDAGISel::selectAddr16(SDNode *Parent, SDValue Addr,
- SDValue &Base, SDValue &Offset,
- SDValue &Alias) {
+bool Mips16DAGToDAGISel::selectAddr(bool SPAllowed, SDValue Addr, SDValue &Base,
+ SDValue &Offset) {
SDLoc DL(Addr);
EVT ValTy = Addr.getValueType();
- Alias = CurDAG->getTargetConstant(0, DL, ValTy);
-
// if Address is FI, get the TargetFrameIndex.
- if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
- Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
- Offset = CurDAG->getTargetConstant(0, DL, ValTy);
- getMips16SPRefReg(Parent, Alias);
- return true;
+ if (SPAllowed) {
+ if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
+ Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
+ Offset = CurDAG->getTargetConstant(0, DL, ValTy);
+ return true;
+ }
}
// on PIC code Load GA
if (Addr.getOpcode() == MipsISD::Wrapper) {
if (CurDAG->isBaseWithConstantOffset(Addr)) {
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
if (isInt<16>(CN->getSExtValue())) {
-
// If the first operand is a FI, get the TargetFI Node
- if (FrameIndexSDNode *FIN =
- dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
- Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
- getMips16SPRefReg(Parent, Alias);
- } else
- Base = Addr.getOperand(0);
+ if (SPAllowed) {
+ if (FrameIndexSDNode *FIN =
+ dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
+ Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
+ Offset = CurDAG->getTargetConstant(CN->getZExtValue(), DL, ValTy);
+ return true;
+ }
+ }
+ Base = Addr.getOperand(0);
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), DL, ValTy);
return true;
}
return true;
}
}
-
- // If an indexed floating point load/store can be emitted, return false.
- const LSBaseSDNode *LS = dyn_cast<LSBaseSDNode>(Parent);
-
- if (LS) {
- if (LS->getMemoryVT() == MVT::f32 && Subtarget->hasMips4_32r2())
- return false;
- if (LS->getMemoryVT() == MVT::f64 && Subtarget->hasMips4_32r2())
- return false;
- }
}
Base = Addr;
Offset = CurDAG->getTargetConstant(0, DL, ValTy);
return true;
}
+bool Mips16DAGToDAGISel::selectAddr16(SDValue Addr, SDValue &Base,
+ SDValue &Offset) {
+ return selectAddr(false, Addr, Base, Offset);
+}
+
+bool Mips16DAGToDAGISel::selectAddr16SP(SDValue Addr, SDValue &Base,
+ SDValue &Offset) {
+ return selectAddr(true, Addr, Base, Offset);
+}
+
/// Select instructions not customized! Used for
/// expanded, promoted and normal instructions
bool Mips16DAGToDAGISel::trySelect(SDNode *Node) {
const SDLoc &DL, EVT Ty, bool HasLo,
bool HasHi);
- SDValue getMips16SPAliasReg();
-
bool runOnMachineFunction(MachineFunction &MF) override;
- void getMips16SPRefReg(SDNode *Parent, SDValue &AliasReg);
-
- bool selectAddr16(SDNode *Parent, SDValue N, SDValue &Base, SDValue &Offset,
- SDValue &Alias) override;
+ bool selectAddr(bool SPAllowed, SDValue Addr, SDValue &Base,
+ SDValue &Offset);
+ bool selectAddr16(SDValue Addr, SDValue &Base,
+ SDValue &Offset) override;
+ bool selectAddr16SP(SDValue Addr, SDValue &Base,
+ SDValue &Offset) override;
bool trySelect(SDNode *Node) override;
//
// Mips Address
//
-def addr16 :
- ComplexPattern<iPTR, 3, "selectAddr16", [frameindex], [SDNPWantParent]>;
+def addr16 : ComplexPattern<iPTR, 2, "selectAddr16", [frameindex]>;
+def addr16sp : ComplexPattern<iPTR, 2, "selectAddr16SP", [frameindex]>;
//
// Address operand
def mem16 : Operand<i32> {
let PrintMethod = "printMemOperand";
- let MIOperandInfo = (ops CPU16Regs, simm16, CPU16RegsPlusSP);
+ let MIOperandInfo = (ops CPU16Regs, simm16);
+ let EncoderMethod = "getMemEncoding";
+}
+
+def mem16sp : Operand<i32> {
+ let PrintMethod = "printMemOperand";
+ // This should be CPUSPReg but the MIPS16 subtarget isn't good enough at
+ // keeping the sp-relative load and the other varieties separate at the
+ // moment. This lie fixes the problem sufficiently well to fix the errors
+ // emitted by -verify-machineinstrs and the output ends up correct as long
+ // as we use an external assembler (which is already a requirement for MIPS16
+ // for several other reasons).
+ let MIOperandInfo = (ops CPU16RegsPlusSP, simm16);
let EncoderMethod = "getMemEncoding";
}
let Constraints = "$rx_ = $rx";
}
-
-// this has an explicit sp argument that we ignore to work around a problem
-// in the compiler
-class FEXT_RI16_SP_explicit_ins<bits<5> _op, string asmstr,
- InstrItinClass itin>:
- FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins CPUSPReg:$ry, simm16:$imm),
- !strconcat(asmstr, "\t$rx, $imm ( $ry ); "), [], itin>;
-
-class FEXT_RI16_SP_Store_explicit_ins<bits<5> _op, string asmstr,
- InstrItinClass itin>:
- FEXT_RI16<_op, (outs), (ins CPU16Regs:$rx, CPUSPReg:$ry, simm16:$imm),
- !strconcat(asmstr, "\t$rx, $imm ( $ry ); "), [], itin>;
-
//
// EXT-RRI instruction format
//
// Purpose: Load Word (SP-Relative, Extended)
// To load an SP-relative word from memory as a signed value.
//
-def LwRxSpImmX16: FEXT_RI16_SP_explicit_ins<0b10010, "lw", II_LW>, MayLoad{
- let Uses = [SP];
-}
+def LwRxSpImmX16: FEXT_RRI16_mem_ins<0b10010, "lw", mem16sp, II_LW>, MayLoad;
def LwRxPcTcp16: FRI16_TCP_ins<0b10110, "lw", II_LW>, MayLoad;
// Purpose: Store Word (Extended)
// To store a word to memory.
//
-def SwRxRyOffMemX16:
- FEXT_RRI16_mem2_ins<0b11011, "sw", mem16, II_SW>, MayStore;
+def SwRxRyOffMemX16: FEXT_RRI16_mem2_ins<0b11011, "sw", mem16, II_SW>, MayStore;
//
// Format: SW rx, offset(sp) MIPS16e
// Purpose: Store Word rx (SP-Relative)
// To store an SP-relative word to memory.
//
-def SwRxSpImmX16: FEXT_RI16_SP_Store_explicit_ins
- <0b11010, "sw", II_SW>, MayStore;
+def SwRxSpImmX16: FEXT_RRI16_mem2_ins<0b11010, "sw", mem16sp, II_SW>, MayStore;
//
//
def: shift_rotate_reg16_pat<sra, SravRxRy16>;
def: shift_rotate_reg16_pat<srl, SrlvRxRy16>;
-class LoadM16_pat<PatFrag OpNode, Instruction I> :
- Mips16Pat<(OpNode addr16:$addr), (I addr16:$addr)>;
+class LoadM16_pat<PatFrag OpNode, Instruction I, ComplexPattern Addr> :
+ Mips16Pat<(OpNode Addr:$addr), (I Addr:$addr)>;
-def: LoadM16_pat<sextloadi8, LbRxRyOffMemX16>;
-def: LoadM16_pat<zextloadi8, LbuRxRyOffMemX16>;
-def: LoadM16_pat<sextloadi16, LhRxRyOffMemX16>;
-def: LoadM16_pat<zextloadi16, LhuRxRyOffMemX16>;
-def: LoadM16_pat<load, LwRxRyOffMemX16>;
+def: LoadM16_pat<sextloadi8, LbRxRyOffMemX16, addr16>;
+def: LoadM16_pat<zextloadi8, LbuRxRyOffMemX16, addr16>;
+def: LoadM16_pat<sextloadi16, LhRxRyOffMemX16, addr16>;
+def: LoadM16_pat<zextloadi16, LhuRxRyOffMemX16, addr16>;
+def: LoadM16_pat<load, LwRxSpImmX16, addr16sp>;
-class StoreM16_pat<PatFrag OpNode, Instruction I> :
- Mips16Pat<(OpNode CPU16Regs:$r, addr16:$addr),
- (I CPU16Regs:$r, addr16:$addr)>;
+class StoreM16_pat<PatFrag OpNode, Instruction I, ComplexPattern Addr> :
+ Mips16Pat<(OpNode CPU16Regs:$r, Addr:$addr), (I CPU16Regs:$r, Addr:$addr)>;
-def: StoreM16_pat<truncstorei8, SbRxRyOffMemX16>;
-def: StoreM16_pat<truncstorei16, ShRxRyOffMemX16>;
-def: StoreM16_pat<store, SwRxRyOffMemX16>;
+def: StoreM16_pat<truncstorei8, SbRxRyOffMemX16, addr16>;
+def: StoreM16_pat<truncstorei16, ShRxRyOffMemX16, addr16>;
+def: StoreM16_pat<store, SwRxSpImmX16, addr16sp>;
// Unconditional branch
class UncondBranch16_pat<SDNode OpNode, Instruction I>:
(I CPU16Regs:$rx, imm_type:$imm16)>;
-def: Mips16Pat<(i32 addr16:$addr),
- (AddiuRxRyOffMemX16 addr16:$addr)>;
+def: Mips16Pat<(i32 addr16sp:$addr), (AddiuRxRyOffMemX16 addr16sp:$addr)>;
// Large (>16 bit) immediate loads
return false;
}
-bool MipsDAGToDAGISel::selectAddr16(SDNode *Parent, SDValue N, SDValue &Base,
- SDValue &Offset, SDValue &Alias) {
+bool MipsDAGToDAGISel::selectAddr16(SDValue Addr, SDValue &Base,
+ SDValue &Offset) {
+ llvm_unreachable("Unimplemented function.");
+ return false;
+}
+
+bool MipsDAGToDAGISel::selectAddr16SP(SDValue Addr, SDValue &Base,
+ SDValue &Offset) {
llvm_unreachable("Unimplemented function.");
return false;
}
virtual bool selectIntAddrMSA(SDValue Addr, SDValue &Base,
SDValue &Offset) const;
- virtual bool selectAddr16(SDNode *Parent, SDValue N, SDValue &Base,
- SDValue &Offset, SDValue &Alias);
+ virtual bool selectAddr16(SDValue Addr, SDValue &Base, SDValue &Offset);
+ virtual bool selectAddr16SP(SDValue Addr, SDValue &Base, SDValue &Offset);
/// \brief Select constant vector splats.
virtual bool selectVSplat(SDNode *N, APInt &Imm,
return GlobalBaseReg = MF.getRegInfo().createVirtualRegister(RC);
}
-bool MipsFunctionInfo::mips16SPAliasRegSet() const {
- return Mips16SPAliasReg;
-}
-unsigned MipsFunctionInfo::getMips16SPAliasReg() {
- // Return if it has already been initialized.
- if (Mips16SPAliasReg)
- return Mips16SPAliasReg;
-
- const TargetRegisterClass *RC = &Mips::CPU16RegsRegClass;
- return Mips16SPAliasReg = MF.getRegInfo().createVirtualRegister(RC);
-}
-
void MipsFunctionInfo::createEhDataRegsFI() {
for (int I = 0; I < 4; ++I) {
const TargetRegisterClass *RC =
class MipsFunctionInfo : public MachineFunctionInfo {
public:
MipsFunctionInfo(MachineFunction &MF)
- : MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0),
- VarArgsFrameIndex(0), CallsEhReturn(false), IsISR(false), SaveS2(false),
+ : MF(MF), SRetReturnReg(0), GlobalBaseReg(0), VarArgsFrameIndex(0),
+ CallsEhReturn(false), IsISR(false), SaveS2(false),
MoveF64ViaSpillFI(-1) {}
~MipsFunctionInfo();
bool globalBaseRegSet() const;
unsigned getGlobalBaseReg();
- bool mips16SPAliasRegSet() const;
- unsigned getMips16SPAliasReg();
-
int getVarArgsFrameIndex() const { return VarArgsFrameIndex; }
void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; }
/// relocation models.
unsigned GlobalBaseReg;
- /// Mips16SPAliasReg - keeps track of the virtual register initialized for
- /// use as an alias for SP for use in load/store of halfword/byte from/to
- /// the stack
- unsigned Mips16SPAliasReg;
-
/// VarArgsFrameIndex - FrameIndex for start of varargs area.
int VarArgsFrameIndex;
%v0 = SllX16 killed %v0, 16
%v0 = AdduRxRyRz16 killed %v1, killed %v0
; CHECK-LABEL: name: test
- ; CHECK: %v1 = LwRxRyOffMemX16 %v0, @foo, 0 :: (load 4 from call-entry @foo)
- %v1 = LwRxRyOffMemX16 %v0, @foo, 0 :: (load 4 from call-entry @foo)
+ ; CHECK: %v1 = LwRxRyOffMemX16 %v0, @foo :: (load 4 from call-entry @foo)
+ %v1 = LwRxRyOffMemX16 %v0, @foo :: (load 4 from call-entry @foo)
%t9 = COPY %v1
%gp = COPY killed %v0
JumpLinkReg16 killed %v1, csr_o32, implicit-def %ra, implicit killed %t9, implicit %a0, implicit killed %gp, implicit-def %sp, implicit-def dead %v0
%v0, %v1 = GotPrologue16 $_gp_disp, $_gp_disp
%v0 = SllX16 killed %v0, 16
%s0 = AdduRxRyRz16 killed %v1, killed %v0
- %v0 = LwRxRyOffMemX16 %s0, @g, 0 :: (load 4 from call-entry @g)
+ %v0 = LwRxRyOffMemX16 %s0, @g :: (load 4 from call-entry @g)
; CHECK-LABEL: test2
- ; CHECK: %v1 = LwRxRyOffMemX16 %s0, $__mips16_call_stub_sf_0, 0 :: (load 4 from call-entry $__mips16_call_stub_sf_0)
- %v1 = LwRxRyOffMemX16 %s0, $__mips16_call_stub_sf_0, 0 :: (load 4 from call-entry $__mips16_call_stub_sf_0)
+ ; CHECK: %v1 = LwRxRyOffMemX16 %s0, $__mips16_call_stub_sf_0 :: (load 4 from call-entry $__mips16_call_stub_sf_0)
+ %v1 = LwRxRyOffMemX16 %s0, $__mips16_call_stub_sf_0 :: (load 4 from call-entry $__mips16_call_stub_sf_0)
%gp = COPY %s0
JumpLinkReg16 killed %v1, csr_o32, implicit-def %ra, implicit %v0, implicit killed %gp, implicit-def %sp, implicit-def %v0
- %v1 = LwRxRyOffMemX16 %s0, @__mips16_ret_sf, 0 :: (load 4 from call-entry @__mips16_ret_sf)
+ %v1 = LwRxRyOffMemX16 %s0, @__mips16_ret_sf :: (load 4 from call-entry @__mips16_ret_sf)
%t9 = COPY %v1
%gp = COPY killed %s0
JumpLinkReg16 killed %v1, csr_mips16rethelper, implicit-def %ra, implicit killed %t9, implicit %v0, implicit killed %gp, implicit-def %sp
@sp = common global i16* null, align 4
@cp = common global i8* null, align 4
-define void @p1(i16 signext %s, i8 signext %c) nounwind {
-entry:
- %conv = sext i16 %s to i32
- %conv1 = sext i8 %c to i32
- %call = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str, i32 0, i32 0), i32 %conv, i32 %conv1) nounwind
- ret void
-}
-
declare i32 @printf(i8* nocapture, ...) nounwind
-define void @p2() nounwind {
-entry:
- %0 = load i16*, i16** @sp, align 4
- %1 = load i16, i16* %0, align 2
- %2 = load i8*, i8** @cp, align 4
- %3 = load i8, i8* %2, align 1
- %conv.i = sext i16 %1 to i32
- %conv1.i = sext i8 %3 to i32
- %call.i = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str, i32 0, i32 0), i32 %conv.i, i32 %conv1.i) nounwind
- %4 = load i16*, i16** @sp, align 4
- store i16 32, i16* %4, align 2
- %5 = load i8*, i8** @cp, align 4
- store i8 97, i8* %5, align 1
- ret void
-}
-
define void @test() nounwind {
entry:
%s = alloca i16, align 4
; 16_h: lh ${{[0-9]+}}, [[offset2]](${{[0-9]+}})
}
-define i32 @main() nounwind {
-entry:
- %s.i = alloca i16, align 4
- %c.i = alloca i8, align 4
- %0 = bitcast i16* %s.i to i8*
- call void @llvm.lifetime.start(i64 -1, i8* %0) nounwind
- call void @llvm.lifetime.start(i64 -1, i8* %c.i) nounwind
- store i16 16, i16* %s.i, align 4
- store i8 99, i8* %c.i, align 4
- store i16* %s.i, i16** @sp, align 4
- store i8* %c.i, i8** @cp, align 4
- %call.i.i.i = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str, i32 0, i32 0), i32 16, i32 99) nounwind
- %1 = load i16*, i16** @sp, align 4
- store i16 32, i16* %1, align 2
- %2 = load i8*, i8** @cp, align 4
- store i8 97, i8* %2, align 1
- %3 = load i16, i16* %s.i, align 4
- %4 = load i8, i8* %c.i, align 4
- %conv.i.i = sext i16 %3 to i32
- %conv1.i.i = sext i8 %4 to i32
- %call.i.i = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str, i32 0, i32 0), i32 %conv.i.i, i32 %conv1.i.i) nounwind
- call void @llvm.lifetime.end(i64 -1, i8* %0) nounwind
- call void @llvm.lifetime.end(i64 -1, i8* %c.i) nounwind
- ret i32 0
-}
-
declare void @llvm.lifetime.start(i64, i8* nocapture) nounwind
declare void @llvm.lifetime.end(i64, i8* nocapture) nounwind
%call7 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @.str, i32 0, i32 0), i32 %0, i32 %1, i32 %add, i32 %add1, i32 %sub, i32 %add2, i32 %add3, i32 %sub4, i32 %sub5, i32 %add6) nounwind
ret i32 0
}
-; 16: sw ${{[0-9]+}}, {{[0-9]+}} ( $sp ); # 4-byte Folded Spill
-; 16: lw ${{[0-9]+}}, {{[0-9]+}} ( $sp ); # 4-byte Folded Reload
-; 16: sw ${{[0-9]+}}, {{[0-9]+}} ( $sp ); # 4-byte Folded Spill
-; 16: lw ${{[0-9]+}}, {{[0-9]+}} ( $sp ); # 4-byte Folded Reload
+; 16: sw ${{[0-9]+}}, {{[0-9]+}}($sp) # 4-byte Folded Spill
+; 16: lw ${{[0-9]+}}, {{[0-9]+}}($sp) # 4-byte Folded Reload
+; 16: sw ${{[0-9]+}}, {{[0-9]+}}($sp) # 4-byte Folded Spill
+; 16: lw ${{[0-9]+}}, {{[0-9]+}}($sp) # 4-byte Folded Reload
declare i32 @printf(i8* nocapture, ...) nounwind
-; RUN: llc -march=mipsel -relocation-model=pic -enable-mips-tail-calls < %s | \
-; RUN: FileCheck %s -check-prefix=PIC32
-; RUN: llc -march=mipsel -relocation-model=static \
-; RUN: -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=STATIC32
+; RUN: llc -march=mipsel -relocation-model=pic -enable-mips-tail-calls \
+; RUN: -verify-machineinstrs < %s | FileCheck %s -check-prefix=PIC32
+; RUN: llc -march=mipsel -relocation-model=static -enable-mips-tail-calls \
+; RUN: -verify-machineinstrs < %s | FileCheck %s -check-prefix=STATIC32
; RUN: llc -march=mips64el -mcpu=mips64r2 -enable-mips-tail-calls \
-; RUN: < %s | FileCheck %s -check-prefix=N64
+; RUN: -verify-machineinstrs < %s | FileCheck %s -check-prefix=N64
; RUN: llc -march=mipsel -mattr=mips16 -relocation-model=pic \
-; RUN: -enable-mips-tail-calls < %s | FileCheck %s -check-prefix=PIC16
+; RUN: -enable-mips-tail-calls -verify-machineinstrs < %s | \
+; RUN: FileCheck %s -check-prefix=PIC16
@g0 = common global i32 0, align 4
@g1 = common global i32 0, align 4