This patch is for the implementation of mips16 complex pattern addr16.

Previously mips16 was sharing the pattern addr which is used for mips32
and mips64. This had a number of problems:
1) Storing and loading byte and halfword quantities for mips16 has particular
problems due to the primarily non mips16 nature of SP. When we must
load/store byte/halfword stack objects in a function, we must create a mips16
alias register for SP. This functionality is tested in stchar.ll.
2) We need to have an FP register under certain conditions (such as 
dynamically sized alloca). We use mips16 register S0 for this purpose.
In this case, we also use this register when accessing frame objects so this
issue also affects the complex pattern addr16. This functionality is
tested in alloca16.ll.

The Mips16InstrInfo.td has been updated to use addr16 instead of addr.

The complex pattern C++ function for addr has been copied to addr16 and
updated to reflect the above issues.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@166897 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Reed Kotler 2012-10-28 06:02:37 +00:00
parent 163f67f4d9
commit f99998a2b0
9 changed files with 409 additions and 48 deletions

View File

@ -41,6 +41,11 @@ void Mips16FrameLowering::emitPrologue(MachineFunction &MF) const {
// Adjust stack.
if (isInt<16>(-StackSize))
BuildMI(MBB, MBBI, dl, TII.get(Mips::SaveRaF16)).addImm(StackSize);
if (hasFP(MF))
BuildMI(MBB, MBBI, dl, TII.get(Mips::MoveR3216), Mips::S0)
.addReg(Mips::SP);
}
void Mips16FrameLowering::emitEpilogue(MachineFunction &MF,
@ -55,6 +60,10 @@ void Mips16FrameLowering::emitEpilogue(MachineFunction &MF,
if (!StackSize)
return;
if (hasFP(MF))
BuildMI(MBB, MBBI, dl, TII.get(Mips::Move32R16), Mips::SP)
.addReg(Mips::S0);
// Adjust stack.
if (isInt<16>(StackSize))
// assumes stacksize multiple of 8

View File

@ -11,11 +11,22 @@
//
//===----------------------------------------------------------------------===//
//
//
// Mips Address
//
def addr16 :
ComplexPattern<iPTR, 3, "SelectAddr16", [frameindex], [SDNPWantParent]>;
//
// Address operand
def mem16 : Operand<i32> {
let PrintMethod = "printMemOperand";
let MIOperandInfo = (ops CPU16Regs, simm16, CPU16Regs);
let EncoderMethod = "getMemEncoding";
}
def mem16_ea : Operand<i32> {
let PrintMethod = "printMemOperandEA";
let MIOperandInfo = (ops CPU16Regs, simm16);
let EncoderMethod = "getMemEncoding";
}
@ -118,6 +129,16 @@ class FEXT_RRI16_mem2_ins<bits<5> op, string asmstr, Operand MemOpnd,
FEXT_RRI16<op, (outs ), (ins CPU16Regs:$ry, MemOpnd:$addr),
!strconcat(asmstr, "\t$ry, $addr"), [], itin>;
//
//
// EXT-RRI-A instruction format
//
class FEXT_RRI_A16_mem_ins<bits<1> op, string asmstr, Operand MemOpnd,
InstrItinClass itin>:
FEXT_RRI_A16<op, (outs CPU16Regs:$ry), (ins MemOpnd:$addr),
!strconcat(asmstr, "\t$ry, $addr"), [], itin>;
//
// EXT-SHIFT instruction format
//
@ -367,6 +388,9 @@ def AddiuRxImmX16: FEXT_RI16_ins<0b01001, "addiu", IIAlu>;
def AddiuRxRxImmX16: FEXT_2RI16_ins<0b01001, "addiu", IIAlu>,
ArithLogic16Defs<0>;
def AddiuRxRyOffMemX16:
FEXT_RRI_A16_mem_ins<0, "addiu", mem16_ea, IIAlu>;
//
// Format: ADDIU rx, pc, immediate MIPS16e
@ -477,8 +501,13 @@ def DivuRxRy16: FRR16_div_ins<0b11011, "divu", IIAlu> {
// address register.
//
def JrRa16: FRR16_JALRC_RA_only_ins<0, 0, "jr", IIAlu>;
def JrRa16: FRR16_JALRC_RA_only_ins<0, 0, "jr", IIAlu> {
let isBranch = 1;
let isIndirectBranch = 1;
let hasDelaySlot = 1;
let isTerminator=1;
let isBarrier=1;
}
//
// Format: LB ry, offset(rx) MIPS16e
// Purpose: Load Byte (Extended)
@ -940,7 +969,7 @@ def: shift_rotate_reg16_pat<sra, SravRxRy16>;
def: shift_rotate_reg16_pat<srl, SrlvRxRy16>;
class LoadM16_pat<PatFrag OpNode, Instruction I> :
Mips16Pat<(OpNode addr:$addr), (I addr:$addr)>;
Mips16Pat<(OpNode addr16:$addr), (I addr16:$addr)>;
def: LoadM16_pat<sextloadi8, LbRxRyOffMemX16>;
def: LoadM16_pat<zextloadi8, LbuRxRyOffMemX16>;
@ -949,7 +978,8 @@ def: LoadM16_pat<zextloadi16, LhuRxRyOffMemX16>;
def: LoadM16_pat<load, LwRxRyOffMemX16>;
class StoreM16_pat<PatFrag OpNode, Instruction I> :
Mips16Pat<(OpNode CPU16Regs:$r, addr:$addr), (I CPU16Regs:$r, addr:$addr)>;
Mips16Pat<(OpNode CPU16Regs:$r, addr16:$addr),
(I CPU16Regs:$r, addr16:$addr)>;
def: StoreM16_pat<truncstorei8, SbRxRyOffMemX16>;
def: StoreM16_pat<truncstorei16, ShRxRyOffMemX16>;
@ -983,6 +1013,11 @@ class SetCC_I16<PatFrag cond_op, PatLeaf imm_type, Instruction I>:
Mips16Pat<(cond_op CPU16Regs:$rx, imm_type:$imm16),
(I CPU16Regs:$rx, imm_type:$imm16)>;
def: Mips16Pat<(i32 addr16:$addr),
(AddiuRxRyOffMemX16 addr16:$addr)>;
// Large (>16 bit) immediate loads
def : Mips16Pat<(i32 imm:$imm),
(OrRxRxRy16 (SllX16 (LiRxImmX16 (HI16 imm:$imm)), 16),
@ -1451,5 +1486,6 @@ class Wrapper16Pat<SDNode node, Instruction ADDiuOp, RegisterClass RC>:
(ADDiuOp RC:$gp, node:$in)>;
def : Wrapper16Pat<tglobaladdr, AddiuRxRxImmX16, CPU16Regs>;
def : Wrapper16Pat<tglobaltlsaddr, AddiuRxRxImmX16, CPU16Regs>;

View File

@ -54,51 +54,60 @@ void Mips16RegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
unsigned OpNo, int FrameIndex,
uint64_t StackSize,
int64_t SPOffset) const {
MachineInstr &MI = *II;
MachineFunction &MF = *MI.getParent()->getParent();
MachineFrameInfo *MFI = MF.getFrameInfo();
MachineInstr &MI = *II;
MachineFunction &MF = *MI.getParent()->getParent();
MachineFrameInfo *MFI = MF.getFrameInfo();
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
int MinCSFI = 0;
int MaxCSFI = -1;
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
int MinCSFI = 0;
int MaxCSFI = -1;
if (CSI.size()) {
MinCSFI = CSI[0].getFrameIdx();
MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
}
if (CSI.size()) {
MinCSFI = CSI[0].getFrameIdx();
MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
}
// The following stack frame objects are always
// referenced relative to $sp:
// 1. Outgoing arguments.
// 2. Pointer to dynamically allocated stack space.
// 3. Locations for callee-saved registers.
// Everything else is referenced relative to whatever register
// getFrameRegister() returns.
unsigned FrameReg;
// The following stack frame objects are always
// referenced relative to $sp:
// 1. Outgoing arguments.
// 2. Pointer to dynamically allocated stack space.
// 3. Locations for callee-saved registers.
// Everything else is referenced relative to whatever register
// getFrameRegister() returns.
unsigned FrameReg;
if (FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI)
FrameReg = Subtarget.isABI_N64() ? Mips::SP_64 : Mips::SP;
if (FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI)
FrameReg = Mips::SP;
else {
const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
if (TFI->hasFP(MF)) {
FrameReg = Mips::S0;
}
else {
if ((MI.getNumOperands()> OpNo+2) && MI.getOperand(OpNo+2).isReg())
FrameReg = MI.getOperand(OpNo+2).getReg();
else
FrameReg = getFrameRegister(MF);
FrameReg = Mips::SP;
}
}
// Calculate final offset.
// - There is no need to change the offset if the frame object
// is one of the
// following: an outgoing argument, pointer to a dynamically allocated
// stack space or a $gp restore location,
// - If the frame object is any of the following,
// its offset must be adjusted
// by adding the size of the stack:
// incoming argument, callee-saved register location or local variable.
int64_t Offset;
Offset = SPOffset + (int64_t)StackSize;
Offset += MI.getOperand(OpNo + 1).getImm();
// Calculate final offset.
// - There is no need to change the offset if the frame object
// is one of the
// following: an outgoing argument, pointer to a dynamically allocated
// stack space or a $gp restore location,
// - If the frame object is any of the following,
// its offset must be adjusted
// by adding the size of the stack:
// incoming argument, callee-saved register location or local variable.
int64_t Offset;
Offset = SPOffset + (int64_t)StackSize;
Offset += MI.getOperand(OpNo + 1).getImm();
DEBUG(errs() << "Offset : " << Offset << "\n" << "<--------->\n");
DEBUG(errs() << "Offset : " << Offset << "\n" << "<--------->\n");
MI.getOperand(OpNo).ChangeToRegister(FrameReg, false);
MI.getOperand(OpNo + 1).ChangeToImmediate(Offset);
MI.getOperand(OpNo).ChangeToRegister(FrameReg, false);
MI.getOperand(OpNo + 1).ChangeToImmediate(Offset);
}

View File

@ -86,6 +86,10 @@ private:
SDNode *getGlobalBaseReg();
SDValue getMips16SPAliasReg();
void getMips16SPRefReg(SDNode *parent, SDValue &AliasReg);
std::pair<SDNode*, SDNode*> SelectMULT(SDNode *N, unsigned Opc, DebugLoc dl,
EVT Ty, bool HasLo, bool HasHi);
@ -94,6 +98,9 @@ private:
// Complex Pattern.
bool SelectAddr(SDNode *Parent, SDValue N, SDValue &Base, SDValue &Offset);
bool SelectAddr16(SDNode *Parent, SDValue N, SDValue &Base, SDValue &Offset,
SDValue &Alias);
// getImm - Return a target constant with the specified value.
inline SDValue getImm(const SDNode *Node, unsigned Imm) {
return CurDAG->getTargetConstant(Imm, Node->getValueType(0));
@ -102,6 +109,7 @@ private:
void ProcessFunctionAfterISel(MachineFunction &MF);
bool ReplaceUsesWithZeroReg(MachineRegisterInfo *MRI, const MachineInstr&);
void InitGlobalBaseReg(MachineFunction &MF);
void InitMips16SPAliasReg(MachineFunction &MF);
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op,
char ConstraintCode,
@ -220,6 +228,26 @@ void MipsDAGToDAGISel::InitGlobalBaseReg(MachineFunction &MF) {
.addReg(Mips::V0).addReg(Mips::T9);
}
// Insert instructions to initialize the Mips16 SP Alias register in the
// first MBB of the function.
//
void MipsDAGToDAGISel::InitMips16SPAliasReg(MachineFunction &MF) {
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
if (!MipsFI->mips16SPAliasRegSet())
return;
MachineBasicBlock &MBB = MF.front();
MachineBasicBlock::iterator I = MBB.begin();
const TargetInstrInfo &TII = *MF.getTarget().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);
}
bool MipsDAGToDAGISel::ReplaceUsesWithZeroReg(MachineRegisterInfo *MRI,
const MachineInstr& MI) {
unsigned DstReg = 0, ZeroReg = 0;
@ -260,6 +288,7 @@ bool MipsDAGToDAGISel::ReplaceUsesWithZeroReg(MachineRegisterInfo *MRI,
void MipsDAGToDAGISel::ProcessFunctionAfterISel(MachineFunction &MF) {
InitGlobalBaseReg(MF);
InitMips16SPAliasReg(MF);
MachineRegisterInfo *MRI = &MF.getRegInfo();
@ -284,6 +313,14 @@ SDNode *MipsDAGToDAGISel::getGlobalBaseReg() {
return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode();
}
/// getMips16SPAliasReg - Output the instructions required to put the
/// SP into a Mips16 accessible aliased register.
SDValue MipsDAGToDAGISel::getMips16SPAliasReg() {
unsigned Mips16SPAliasReg =
MF->getInfo<MipsFunctionInfo>()->getMips16SPAliasReg();
return CurDAG->getRegister(Mips16SPAliasReg, TLI.getPointerTy());
}
/// ComplexPattern used on MipsInstrInfo
/// Used on Mips Load/Store instructions
bool MipsDAGToDAGISel::
@ -362,6 +399,115 @@ SelectAddr(SDNode *Parent, SDValue Addr, SDValue &Base, SDValue &Offset) {
return true;
}
void MipsDAGToDAGISel::getMips16SPRefReg(SDNode *Parent, SDValue &AliasReg) {
SDValue AliasFPReg = CurDAG->getRegister(Mips::S0, TLI.getPointerTy());
if (Parent) {
switch (Parent->getOpcode()) {
case ISD::LOAD: {
LoadSDNode *SD = dyn_cast<LoadSDNode>(Parent);
switch (SD->getMemoryVT().getSizeInBits()) {
case 8:
case 16:
AliasReg = TM.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 = TM.getFrameLowering()->hasFP(*MF)?
AliasFPReg: getMips16SPAliasReg();
return;
}
break;
}
}
}
AliasReg = CurDAG->getRegister(Mips::SP, TLI.getPointerTy());
return;
}
bool MipsDAGToDAGISel::SelectAddr16(
SDNode *Parent, SDValue Addr, SDValue &Base, SDValue &Offset,
SDValue &Alias) {
EVT ValTy = Addr.getValueType();
Alias = CurDAG->getTargetConstant(0, 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, ValTy);
getMips16SPRefReg(Parent, Alias);
return true;
}
// on PIC code Load GA
if (Addr.getOpcode() == MipsISD::Wrapper) {
Base = Addr.getOperand(0);
Offset = Addr.getOperand(1);
return true;
}
if (TM.getRelocationModel() != Reloc::PIC_) {
if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
Addr.getOpcode() == ISD::TargetGlobalAddress))
return false;
}
// Addresses of the form FI+const or FI|const
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);
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), ValTy);
return true;
}
}
// Operand is a result from an ADD.
if (Addr.getOpcode() == ISD::ADD) {
// When loading from constant pools, load the lower address part in
// the instruction itself. Example, instead of:
// lui $2, %hi($CPI1_0)
// addiu $2, $2, %lo($CPI1_0)
// lwc1 $f0, 0($2)
// Generate:
// lui $2, %hi($CPI1_0)
// lwc1 $f0, %lo($CPI1_0)($2)
if (Addr.getOperand(1).getOpcode() == MipsISD::Lo ||
Addr.getOperand(1).getOpcode() == MipsISD::GPRel) {
SDValue Opnd0 = Addr.getOperand(1).getOperand(0);
if (isa<ConstantPoolSDNode>(Opnd0) || isa<GlobalAddressSDNode>(Opnd0) ||
isa<JumpTableSDNode>(Opnd0)) {
Base = Addr.getOperand(0);
Offset = Opnd0;
return true;
}
}
// If an indexed floating point load/store can be emitted, return false.
const LSBaseSDNode *LS = dyn_cast<LSBaseSDNode>(Parent);
if (LS &&
(LS->getMemoryVT() == MVT::f32 || LS->getMemoryVT() == MVT::f64) &&
Subtarget.hasMips32r2Or64())
return false;
}
Base = Addr;
Offset = CurDAG->getTargetConstant(0, ValTy);
return true;
}
/// Select multiply instructions.
std::pair<SDNode*, SDNode*>
MipsDAGToDAGISel::SelectMULT(SDNode *N, unsigned Opc, DebugLoc dl, EVT Ty,

View File

@ -43,4 +43,17 @@ unsigned MipsFunctionInfo::getGlobalBaseReg() {
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;
RC=(const TargetRegisterClass*)&Mips::CPU16RegsRegClass;
return Mips16SPAliasReg = MF.getRegInfo().createVirtualRegister(RC);
}
void MipsFunctionInfo::anchor() { }

View File

@ -39,6 +39,11 @@ class MipsFunctionInfo : public MachineFunctionInfo {
/// 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;
@ -46,8 +51,8 @@ class MipsFunctionInfo : public MachineFunctionInfo {
public:
MipsFunctionInfo(MachineFunction& MF)
: MF(MF), SRetReturnReg(0), GlobalBaseReg(0),
VarArgsFrameIndex(0), EmitNOAT(false)
: MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0),
VarArgsFrameIndex(0), EmitNOAT(false)
{}
unsigned getSRetReturnReg() const { return SRetReturnReg; }
@ -56,6 +61,9 @@ public:
bool globalBaseRegSet() const;
unsigned getGlobalBaseReg();
bool mips16SPAliasRegSet() const;
unsigned getMips16SPAliasReg();
int getVarArgsFrameIndex() const { return VarArgsFrameIndex; }
void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; }

View File

@ -112,11 +112,14 @@ getReservedRegs(const MachineFunction &MF) const {
EReg = Mips::FGR64RegClass.end(); Reg != EReg; ++Reg)
Reserved.set(*Reg);
}
// Reserve FP if this function should have a dedicated frame pointer register.
if (MF.getTarget().getFrameLowering()->hasFP(MF)) {
Reserved.set(Mips::FP);
Reserved.set(Mips::FP_64);
if (Subtarget.inMips16Mode())
Reserved.set(Mips::S0);
else {
Reserved.set(Mips::FP);
Reserved.set(Mips::FP_64);
}
}
// Reserve hardware registers.
@ -186,8 +189,12 @@ getFrameRegister(const MachineFunction &MF) const {
const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
bool IsN64 = Subtarget.isABI_N64();
return TFI->hasFP(MF) ? (IsN64 ? Mips::FP_64 : Mips::FP) :
(IsN64 ? Mips::SP_64 : Mips::SP);
if (Subtarget.inMips16Mode())
return TFI->hasFP(MF) ? Mips::S0 : Mips::SP;
else
return TFI->hasFP(MF) ? (IsN64 ? Mips::FP_64 : Mips::FP) :
(IsN64 ? Mips::SP_64 : Mips::SP);
}
unsigned MipsRegisterInfo::

View File

@ -0,0 +1,43 @@
; RUN: llc -march=mipsel -mcpu=mips16 -relocation-model=pic -O3 < %s | FileCheck %s -check-prefix=16
@iiii = global i32 25, align 4
@jjjj = global i32 35, align 4
@kkkk = global i32 100, align 4
@riii = common global i32 0, align 4
@rjjj = common global i32 0, align 4
@rkkk = common global i32 0, align 4
define void @test() nounwind {
entry:
; 16: .frame $16,16,$ra
; 16: save $ra, $s0, $s1, 16
; 16: move $16, $sp
; 16: move ${{[0-9]+}}, $sp
; 16: subu $[[REGISTER:[0-9]+]], ${{[0-9]+}}, ${{[0-9]+}}
; 16: move $sp, $[[REGISTER]]
%0 = load i32* @kkkk, align 4
%1 = mul i32 %0, 25
%2 = alloca i32, i32 %1, align 4
%3 = load i32* @jjjj, align 4
%4 = load i32* @iiii, align 4
%arrayidx = getelementptr inbounds i32* %2, i32 %4
store i32 %3, i32* %arrayidx, align 4
%arrayidx1 = getelementptr inbounds i32* %2, i32 %3
store i32 %0, i32* %arrayidx1, align 4
%arrayidx2 = getelementptr inbounds i32* %2, i32 %0
store i32 %4, i32* %arrayidx2, align 4
%arrayidx3 = getelementptr inbounds i32* %2, i32 25
%5 = load i32* %arrayidx3, align 4
store i32 %5, i32* @riii, align 4
%arrayidx4 = getelementptr inbounds i32* %2, i32 35
%6 = load i32* %arrayidx4, align 4
store i32 %6, i32* @rjjj, align 4
%arrayidx5 = getelementptr inbounds i32* %2, i32 100
%7 = load i32* %arrayidx5, align 4
store i32 %7, i32* @rkkk, align 4
; 16: move $sp, $16
; 16: restore $ra, $s0, $s1, 16
ret void
}

View File

@ -0,0 +1,90 @@
; RUN: llc -march=mipsel -mcpu=mips16 -relocation-model=pic -O3 < %s | FileCheck %s -check-prefix=16_h
; RUN: llc -march=mipsel -mcpu=mips16 -relocation-model=pic -O3 < %s | FileCheck %s -check-prefix=16_b
@.str = private unnamed_addr constant [9 x i8] c"%hd %c \0A\00", align 1
@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]* @.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** @sp, align 4
%1 = load i16* %0, align 2
%2 = load i8** @cp, align 4
%3 = load 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]* @.str, i32 0, i32 0), i32 %conv.i, i32 %conv1.i) nounwind
%4 = load i16** @sp, align 4
store i16 32, i16* %4, align 2
%5 = load i8** @cp, align 4
store i8 97, i8* %5, align 1
ret void
}
define void @test() nounwind {
entry:
%s = alloca i16, align 4
%c = alloca i8, align 4
store i16 16, i16* %s, align 4
store i8 99, i8* %c, align 4
store i16* %s, i16** @sp, align 4
store i8* %c, i8** @cp, align 4
%call.i.i = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i32 16, i32 99) nounwind
%0 = load i16** @sp, align 4
store i16 32, i16* %0, align 2
%1 = load i8** @cp, align 4
store i8 97, i8* %1, align 1
%2 = load i16* %s, align 4
%3 = load i8* %c, align 4
%conv.i = sext i16 %2 to i32
%conv1.i = sext i8 %3 to i32
%call.i = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i32 %conv.i, i32 %conv1.i) nounwind
ret void
; 16_b: test:
; 16_h: test:
; 16_b: sb ${{[0-9]+}}, [[offset1:[0-9]+]](${{[0-9]+}})
; 16_b: lb ${{[0-9]+}}, [[offset1]](${{[0-9]+}})
; 16_h: sh ${{[0-9]+}}, [[offset2:[0-9]+]](${{[0-9]+}})
; 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]* @.str, i32 0, i32 0), i32 16, i32 99) nounwind
%1 = load i16** @sp, align 4
store i16 32, i16* %1, align 2
%2 = load i8** @cp, align 4
store i8 97, i8* %2, align 1
%3 = load i16* %s.i, align 4
%4 = load 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]* @.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