aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/CodeGen/MachineInstrBuilder.h11
-rw-r--r--include/llvm/CodeGen/MachineOperand.h24
-rw-r--r--include/llvm/CodeGen/RegisterScavenging.h15
-rw-r--r--lib/CodeGen/LiveIntervalAnalysis.cpp6
-rw-r--r--lib/CodeGen/MachineInstr.cpp16
-rw-r--r--lib/CodeGen/RegAllocLinearScan.cpp11
-rw-r--r--lib/CodeGen/RegisterScavenging.cpp34
-rw-r--r--lib/CodeGen/SelectionDAG/ScheduleDAGSDNodesEmit.cpp2
-rw-r--r--lib/CodeGen/VirtRegRewriter.cpp48
-rw-r--r--lib/Target/X86/X86InstrInfo.cpp3
-rw-r--r--test/CodeGen/ARM/2009-06-30-RegScavengerAssert.ll122
11 files changed, 213 insertions, 79 deletions
diff --git a/include/llvm/CodeGen/MachineInstrBuilder.h b/include/llvm/CodeGen/MachineInstrBuilder.h
index 3f30de596a..29e90098c9 100644
--- a/include/llvm/CodeGen/MachineInstrBuilder.h
+++ b/include/llvm/CodeGen/MachineInstrBuilder.h
@@ -29,7 +29,8 @@ namespace RegState {
Implicit = 0x4,
Kill = 0x8,
Dead = 0x10,
- EarlyClobber = 0x20,
+ Undef = 0x20,
+ EarlyClobber = 0x40,
ImplicitDefine = Implicit | Define,
ImplicitKill = Implicit | Kill
};
@@ -57,8 +58,9 @@ public:
flags & RegState::Implicit,
flags & RegState::Kill,
flags & RegState::Dead,
- SubReg,
- flags & RegState::EarlyClobber));
+ flags & RegState::Undef,
+ flags & RegState::EarlyClobber,
+ SubReg));
return *this;
}
@@ -203,6 +205,9 @@ inline unsigned getKillRegState(bool B) {
inline unsigned getDeadRegState(bool B) {
return B ? RegState::Dead : 0;
}
+inline unsigned getUndefRegState(bool B) {
+ return B ? RegState::Undef : 0;
+}
} // End llvm namespace
diff --git a/include/llvm/CodeGen/MachineOperand.h b/include/llvm/CodeGen/MachineOperand.h
index 5a7f76b572..08739a2673 100644
--- a/include/llvm/CodeGen/MachineOperand.h
+++ b/include/llvm/CodeGen/MachineOperand.h
@@ -75,6 +75,10 @@ private:
/// This is only valid on definitions of registers.
bool IsDead : 1;
+ /// IsUndef - True if this is a register def / use of "undef", i.e. register
+ /// defined by an IMPLICIT_DEF. This is only valid on registers.
+ bool IsUndef : 1;
+
/// IsEarlyClobber - True if this MO_Register 'def' operand is written to
/// by the MachineInstr before all input registers are read. This is used to
/// model the GCC inline asm '&' constraint modifier.
@@ -198,6 +202,11 @@ public:
return IsKill;
}
+ bool isUndef() const {
+ assert(isReg() && "Wrong MachineOperand accessor");
+ return IsUndef;
+ }
+
bool isEarlyClobber() const {
assert(isReg() && "Wrong MachineOperand accessor");
return IsEarlyClobber;
@@ -248,6 +257,11 @@ public:
IsDead = Val;
}
+ void setIsUndef(bool Val = true) {
+ assert(isReg() && "Wrong MachineOperand accessor");
+ IsUndef = Val;
+ }
+
void setIsEarlyClobber(bool Val = true) {
assert(isReg() && IsDef && "Wrong MachineOperand accessor");
IsEarlyClobber = Val;
@@ -337,7 +351,8 @@ public:
/// the specified value. If an operand is known to be an register already,
/// the setReg method should be used.
void ChangeToRegister(unsigned Reg, bool isDef, bool isImp = false,
- bool isKill = false, bool isDead = false);
+ bool isKill = false, bool isDead = false,
+ bool isUndef = false);
//===--------------------------------------------------------------------===//
// Construction methods.
@@ -357,13 +372,15 @@ public:
static MachineOperand CreateReg(unsigned Reg, bool isDef, bool isImp = false,
bool isKill = false, bool isDead = false,
- unsigned SubReg = 0,
- bool isEarlyClobber = false) {
+ bool isUndef = false,
+ bool isEarlyClobber = false,
+ unsigned SubReg = 0) {
MachineOperand Op(MachineOperand::MO_Register);
Op.IsDef = isDef;
Op.IsImp = isImp;
Op.IsKill = isKill;
Op.IsDead = isDead;
+ Op.IsUndef = isUndef;
Op.IsEarlyClobber = isEarlyClobber;
Op.Contents.Reg.RegNo = Reg;
Op.Contents.Reg.Prev = 0;
@@ -420,6 +437,7 @@ public:
IsImp = MO.IsImp;
IsKill = MO.IsKill;
IsDead = MO.IsDead;
+ IsUndef = MO.IsUndef;
IsEarlyClobber = MO.IsEarlyClobber;
SubReg = MO.SubReg;
ParentMI = MO.ParentMI;
diff --git a/include/llvm/CodeGen/RegisterScavenging.h b/include/llvm/CodeGen/RegisterScavenging.h
index a4ed0129eb..458c2e4487 100644
--- a/include/llvm/CodeGen/RegisterScavenging.h
+++ b/include/llvm/CodeGen/RegisterScavenging.h
@@ -69,10 +69,6 @@ class RegScavenger {
/// available, unset means the register is currently being used.
BitVector RegsAvailable;
- /// ImplicitDefed - If bit is set that means the register is defined by an
- /// implicit_def instructions. That means it can be clobbered at will.
- BitVector ImplicitDefed;
-
/// CurrDist - Distance from MBB entry to the current instruction MBBI.
///
unsigned CurrDist;
@@ -117,25 +113,18 @@ public:
bool isUsed(unsigned Reg) const { return !RegsAvailable[Reg]; }
bool isUnused(unsigned Reg) const { return RegsAvailable[Reg]; }
- bool isImplicitlyDefined(unsigned Reg) const { return ImplicitDefed[Reg]; }
-
/// getRegsUsed - return all registers currently in use in used.
void getRegsUsed(BitVector &used, bool includeReserved);
/// setUsed / setUnused - Mark the state of one or a number of registers.
///
- void setUsed(unsigned Reg, bool ImpDef = false);
- void setUsed(BitVector &Regs, bool ImpDef = false) {
+ void setUsed(unsigned Reg);
+ void setUsed(BitVector &Regs) {
RegsAvailable &= ~Regs;
- if (ImpDef)
- ImplicitDefed |= Regs;
- else
- ImplicitDefed &= ~Regs;
}
void setUnused(unsigned Reg, const MachineInstr *MI);
void setUnused(BitVector &Regs) {
RegsAvailable |= Regs;
- ImplicitDefed &= ~Regs;
}
/// FindUnusedReg - Find a unused register of the specified register class
diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp
index 21bb5dc012..b017f91e6a 100644
--- a/lib/CodeGen/LiveIntervalAnalysis.cpp
+++ b/lib/CodeGen/LiveIntervalAnalysis.cpp
@@ -1782,8 +1782,12 @@ LiveIntervals::handleSpilledImpDefs(const LiveInterval &li, VirtRegMap &vrm,
NewLIs.push_back(&getOrCreateInterval(NewVReg));
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI->getOperand(i);
- if (MO.isReg() && MO.getReg() == li.reg)
+ if (MO.isReg() && MO.getReg() == li.reg) {
MO.setReg(NewVReg);
+ MO.setIsUndef();
+ if (MO.isKill())
+ MO.setIsKill(false);
+ }
}
}
}
diff --git a/lib/CodeGen/MachineInstr.cpp b/lib/CodeGen/MachineInstr.cpp
index c97750847f..d44305f333 100644
--- a/lib/CodeGen/MachineInstr.cpp
+++ b/lib/CodeGen/MachineInstr.cpp
@@ -120,7 +120,7 @@ void MachineOperand::ChangeToImmediate(int64_t ImmVal) {
/// the specified value. If an operand is known to be an register already,
/// the setReg method should be used.
void MachineOperand::ChangeToRegister(unsigned Reg, bool isDef, bool isImp,
- bool isKill, bool isDead) {
+ bool isKill, bool isDead, bool isUndef) {
// If this operand is already a register operand, use setReg to update the
// register's use/def lists.
if (isReg()) {
@@ -143,6 +143,7 @@ void MachineOperand::ChangeToRegister(unsigned Reg, bool isDef, bool isImp,
IsImp = isImp;
IsKill = isKill;
IsDead = isDead;
+ IsUndef = isUndef;
IsEarlyClobber = false;
SubReg = 0;
}
@@ -206,11 +207,11 @@ void MachineOperand::print(raw_ostream &OS, const TargetMachine *TM) const {
OS << "%mreg" << getReg();
}
- if (getSubReg() != 0) {
+ if (getSubReg() != 0)
OS << ':' << getSubReg();
- }
- if (isDef() || isKill() || isDead() || isImplicit() || isEarlyClobber()) {
+ if (isDef() || isKill() || isDead() || isImplicit() || isUndef() ||
+ isEarlyClobber()) {
OS << '<';
bool NeedComma = false;
if (isImplicit()) {
@@ -224,10 +225,15 @@ void MachineOperand::print(raw_ostream &OS, const TargetMachine *TM) const {
OS << "def";
NeedComma = true;
}
- if (isKill() || isDead()) {
+ if (isKill() || isDead() || isUndef()) {
if (NeedComma) OS << ',';
if (isKill()) OS << "kill";
if (isDead()) OS << "dead";
+ if (isUndef()) {
+ if (isKill() || isDead())
+ OS << ',';
+ OS << "undef";
+ }
}
OS << '>';
}
diff --git a/lib/CodeGen/RegAllocLinearScan.cpp b/lib/CodeGen/RegAllocLinearScan.cpp
index 41a42fd22d..2caa2f9d18 100644
--- a/lib/CodeGen/RegAllocLinearScan.cpp
+++ b/lib/CodeGen/RegAllocLinearScan.cpp
@@ -905,6 +905,17 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur)
DOUT << tri_->getName(physReg) << '\n';
// Note the register is not really in use.
vrm_->assignVirt2Phys(cur->reg, physReg);
+ // Since the register allocator is allowed to assign this virtual register
+ // physical register that overlaps other live intervals. Mark these
+ // operands as "Undef" which means later passes, e.g. register scavenger
+ // can ignore them.
+ for (MachineRegisterInfo::reg_iterator RI = mri_->reg_begin(cur->reg),
+ RE = mri_->reg_end(); RI != RE; ++RI) {
+ MachineOperand &MO = RI.getOperand();
+ MO.setIsUndef();
+ if (MO.isKill())
+ MO.setIsKill(false);
+ }
return;
}
diff --git a/lib/CodeGen/RegisterScavenging.cpp b/lib/CodeGen/RegisterScavenging.cpp
index 3feb92fc46..7d8e3afa78 100644
--- a/lib/CodeGen/RegisterScavenging.cpp
+++ b/lib/CodeGen/RegisterScavenging.cpp
@@ -36,7 +36,7 @@ static bool RedefinesSuperRegPart(const MachineInstr *MI, unsigned SubReg,
bool SeenSuperDef = false;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
- if (!MO.isReg())
+ if (!MO.isReg() || MO.isUndef())
continue;
if (TRI->isSuperRegister(SubReg, MO.getReg())) {
if (MO.isUse())
@@ -57,28 +57,22 @@ static bool RedefinesSuperRegPart(const MachineInstr *MI,
}
/// setUsed - Set the register and its sub-registers as being used.
-void RegScavenger::setUsed(unsigned Reg, bool ImpDef) {
+void RegScavenger::setUsed(unsigned Reg) {
RegsAvailable.reset(Reg);
- ImplicitDefed[Reg] = ImpDef;
for (const unsigned *SubRegs = TRI->getSubRegisters(Reg);
- unsigned SubReg = *SubRegs; ++SubRegs) {
+ unsigned SubReg = *SubRegs; ++SubRegs)
RegsAvailable.reset(SubReg);
- ImplicitDefed[SubReg] = ImpDef;
- }
}
/// setUnused - Set the register and its sub-registers as being unused.
void RegScavenger::setUnused(unsigned Reg, const MachineInstr *MI) {
RegsAvailable.set(Reg);
- ImplicitDefed.reset(Reg);
for (const unsigned *SubRegs = TRI->getSubRegisters(Reg);
unsigned SubReg = *SubRegs; ++SubRegs)
- if (!RedefinesSuperRegPart(MI, Reg, TRI)) {
+ if (!RedefinesSuperRegPart(MI, Reg, TRI))
RegsAvailable.set(SubReg);
- ImplicitDefed.reset(SubReg);
- }
}
void RegScavenger::enterBasicBlock(MachineBasicBlock *mbb) {
@@ -94,7 +88,6 @@ void RegScavenger::enterBasicBlock(MachineBasicBlock *mbb) {
if (!MBB) {
NumPhysRegs = TRI->getNumRegs();
RegsAvailable.resize(NumPhysRegs);
- ImplicitDefed.resize(NumPhysRegs);
// Create reserved registers bitvector.
ReservedRegs = TRI->getReservedRegs(MF);
@@ -113,7 +106,6 @@ void RegScavenger::enterBasicBlock(MachineBasicBlock *mbb) {
ScavengeRestore = NULL;
CurrDist = 0;
DistanceMap.clear();
- ImplicitDefed.reset();
// All registers started out unused.
RegsAvailable.set();
@@ -195,15 +187,13 @@ void RegScavenger::forward() {
ScavengeRestore = NULL;
}
- bool IsImpDef = MI->getOpcode() == TargetInstrInfo::IMPLICIT_DEF;
-
// Separate register operands into 3 classes: uses, defs, earlyclobbers.
SmallVector<std::pair<const MachineOperand*,unsigned>, 4> UseMOs;
SmallVector<std::pair<const MachineOperand*,unsigned>, 4> DefMOs;
SmallVector<std::pair<const MachineOperand*,unsigned>, 4> EarlyClobberMOs;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
- if (!MO.isReg() || MO.getReg() == 0)
+ if (!MO.isReg() || MO.getReg() == 0 || MO.isUndef())
continue;
if (MO.isUse())
UseMOs.push_back(std::make_pair(&MO,i));
@@ -221,14 +211,7 @@ void RegScavenger::forward() {
assert(isUsed(Reg) && "Using an undefined register!");
- // Kill of implicit_def defined registers are ignored. e.g.
- // entry: 0x2029ab8, LLVM BB @0x1b06080, ID#0:
- // Live Ins: %R0
- // %R0<def> = IMPLICIT_DEF
- // %R0<def> = IMPLICIT_DEF
- // STR %R0<kill>, %R0, %reg0, 0, 14, %reg0, Mem:ST(4,4) [0x1b06510 + 0]
- // %R1<def> = LDR %R0, %reg0, 24, 14, %reg0, Mem:LD(4,4) [0x1b065bc + 0]
- if (MO.isKill() && !isReserved(Reg) && !isImplicitlyDefined(Reg)) {
+ if (MO.isKill() && !isReserved(Reg)) {
KillRegs.set(Reg);
// Mark sub-registers as used.
@@ -274,10 +257,9 @@ void RegScavenger::forward() {
// Implicit def is allowed to "re-define" any register. Similarly,
// implicitly defined registers can be clobbered.
assert((isReserved(Reg) || isUnused(Reg) ||
- IsImpDef || isImplicitlyDefined(Reg) ||
isLiveInButUnusedBefore(Reg, MI, MBB, TRI, MRI)) &&
"Re-defining a live register!");
- setUsed(Reg, IsImpDef);
+ setUsed(Reg);
}
}
@@ -297,7 +279,7 @@ void RegScavenger::backward() {
SmallVector<std::pair<const MachineOperand*,unsigned>, 4> EarlyClobberMOs;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
- if (!MO.isReg() || MO.getReg() == 0)
+ if (!MO.isReg() || MO.getReg() == 0 || MO.isUndef())
continue;
if (MO.isUse())
UseMOs.push_back(std::make_pair(&MO,i));
diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodesEmit.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodesEmit.cpp
index e372b5b753..79263393a1 100644
--- a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodesEmit.cpp
+++ b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodesEmit.cpp
@@ -617,7 +617,7 @@ void ScheduleDAGSDNodes::EmitNode(SDNode *Node, bool IsClone, bool IsCloned,
for (; NumVals; --NumVals, ++i) {
unsigned Reg = cast<RegisterSDNode>(Node->getOperand(i))->getReg();
MI->addOperand(MachineOperand::CreateReg(Reg, true, false, false,
- false, 0, true));
+ false, false, true));
}
break;
case 1: // Use of register.
diff --git a/lib/CodeGen/VirtRegRewriter.cpp b/lib/CodeGen/VirtRegRewriter.cpp
index bd6584a53c..bbf1e24873 100644
--- a/lib/CodeGen/VirtRegRewriter.cpp
+++ b/lib/CodeGen/VirtRegRewriter.cpp
@@ -356,7 +356,7 @@ static void InvalidateKills(MachineInstr &MI,
SmallVector<unsigned, 2> *KillRegs = NULL) {
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI.getOperand(i);
- if (!MO.isReg() || !MO.isUse() || !MO.isKill())
+ if (!MO.isReg() || !MO.isUse() || !MO.isKill() || MO.isUndef())
continue;
unsigned Reg = MO.getReg();
if (TargetRegisterInfo::isVirtualRegister(Reg))
@@ -390,12 +390,12 @@ static bool InvalidateRegDef(MachineBasicBlock::iterator I,
MachineOperand *DefOp = NULL;
for (unsigned i = 0, e = DefMI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = DefMI->getOperand(i);
- if (MO.isReg() && MO.isDef()) {
- if (MO.getReg() == Reg)
- DefOp = &MO;
- else if (!MO.isDead())
- HasLiveDef = true;
- }
+ if (!MO.isReg() || !MO.isUse() || !MO.isKill() || MO.isUndef())
+ continue;
+ if (MO.getReg() == Reg)
+ DefOp = &MO;
+ else if (!MO.isDead())
+ HasLiveDef = true;
}
if (!DefOp)
return false;
@@ -430,7 +430,7 @@ static void UpdateKills(MachineInstr &MI, const TargetRegisterInfo* TRI,
std::vector<MachineOperand*> &KillOps) {
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI.getOperand(i);
- if (!MO.isReg() || !MO.isUse())
+ if (!MO.isReg() || !MO.isUse() || MO.isUndef())
continue;
unsigned Reg = MO.getReg();
if (Reg == 0)
@@ -1289,8 +1289,7 @@ private:
if (InvalidateRegDef(PrevMII, *MII, KillRegs[j], HasOtherDef)) {
MachineInstr *DeadDef = PrevMII;
if (ReMatDefs.count(DeadDef) && !HasOtherDef) {
- // FIXME: This assumes a remat def does not have side
- // effects.
+ // FIXME: This assumes a remat def does not have side effects.
VRM.RemoveMachineInstrFromMaps(DeadDef);
MBB.erase(DeadDef);
++NumDRM;
@@ -1569,6 +1568,8 @@ private:
if (MO.isImplicit())
// If the virtual register is implicitly defined, emit a implicit_def
// before so scavenger knows it's "defined".
+ // FIXME: This is a horrible hack done the by register allocator to
+ // remat a definition with virtual register operand.
VirtUseOps.insert(VirtUseOps.begin(), i);
else
VirtUseOps.push_back(i);
@@ -1595,6 +1596,7 @@ private:
MI.getOperand(i).setReg(RReg);
MI.getOperand(i).setSubReg(0);
if (VRM.isImplicitlyDefined(VirtReg))
+ // FIXME: Is this needed?
BuildMI(MBB, &MI, MI.getDebugLoc(),
TII->get(TargetInstrInfo::IMPLICIT_DEF), RReg);
continue;
@@ -1604,22 +1606,16 @@ private:
if (!MO.isUse())
continue; // Handle defs in the loop below (handle use&def here though)
- bool AvoidReload = false;
- if (LIs->hasInterval(VirtReg)) {
- LiveInterval &LI = LIs->getInterval(VirtReg);
- if (!LI.liveAt(LIs->getUseIndex(LI.beginNumber())))
- // Must be defined by an implicit def. It should not be spilled. Note,
- // this is for correctness reason. e.g.
- // 8 %reg1024<def> = IMPLICIT_DEF
- // 12 %reg1024<def> = INSERT_SUBREG %reg1024<kill>, %reg1025, 2
- // The live range [12, 14) are not part of the r1024 live interval since
- // it's defined by an implicit def. It will not conflicts with live
- // interval of r1025. Now suppose both registers are spilled, you can
- // easily see a situation where both registers are reloaded before
- // the INSERT_SUBREG and both target registers that would overlap.
- AvoidReload = true;
- }
-
+ bool AvoidReload = MO.isUndef();
+ // Check if it is defined by an implicit def. It should not be spilled.
+ // Note, this is for correctness reason. e.g.
+ // 8 %reg1024<def> = IMPLICIT_DEF
+ // 12 %reg1024<def> = INSERT_SUBREG %reg1024<kill>, %reg1025, 2
+ // The live range [12, 14) are not part of the r1024 live interval since
+ // it's defined by an implicit def. It will not conflicts with live
+ // interval of r1025. Now suppose both registers are spilled, you can
+ // easily see a situation where both registers are reloaded before
+ // the INSERT_SUBREG and both target registers that would overlap.
bool DoReMat = VRM.isReMaterialized(VirtReg);
int SSorRMId = DoReMat
? VRM.getReMatId(VirtReg) : VRM.getStackSlot(VirtReg);
diff --git a/lib/Target/X86/X86InstrInfo.cpp b/lib/Target/X86/X86InstrInfo.cpp
index 21f71ec9a1..e5d84c5077 100644
--- a/lib/Target/X86/X86InstrInfo.cpp
+++ b/lib/Target/X86/X86InstrInfo.cpp
@@ -2459,7 +2459,8 @@ bool X86InstrInfo::unfoldMemoryOperand(MachineFunction &MF, MachineInstr *MI,
getDefRegState(MO.isDef()) |
RegState::Implicit |
getKillRegState(MO.isKill()) |
- getDeadRegState(MO.isDead()));
+ getDeadRegState(MO.isDead()) |
+ getUndefRegState(MO.isUndef()));
}
// Change CMP32ri r, 0 back to TEST32rr r, r, etc.
unsigned NewOpc = 0;
diff --git a/test/CodeGen/ARM/2009-06-30-RegScavengerAssert.ll b/test/CodeGen/ARM/2009-06-30-RegScavengerAssert.ll
new file mode 100644
index 0000000000..27cad7ccf6
--- /dev/null
+++ b/test/CodeGen/ARM/2009-06-30-RegScavengerAssert.ll
@@ -0,0 +1,122 @@
+; RUN: llvm-as < %s | llc -march=arm -mtriple=armv6-apple-darwin9
+
+@nn = external global i32 ; <i32*> [#uses=1]
+@al_len = external global i32 ; <i32*> [#uses=2]
+@no_mat = external global i32 ; <i32*> [#uses=2]
+@no_mis = external global i32 ; <i32*> [#uses=2]
+@"\01LC12" = external constant [29 x i8], align 1 ; <[29 x i8]*> [#uses=1]
+@"\01LC16" = external constant [33 x i8], align 1 ; <[33 x i8]*> [#uses=1]
+@"\01LC17" = external constant [47 x i8], align 1 ; <[47 x i8]*> [#uses=1]
+
+declare arm_apcscc i32 @printf(i8* nocapture, ...) nounwind
+
+declare arm_apcscc void @diff(i8*, i8*, i32, i32, i32, i32) nounwind
+
+define arm_apcscc void @SIM(i8* %A, i8* %B, i32 %M, i32 %N, i32 %K, [256 x i32]* %V, i32 %Q, i32 %R, i32 %nseq) nounwind {
+entry:
+ br i1 undef, label %bb5, label %bb
+
+bb: ; preds = %bb, %entry
+ br label %bb
+
+bb5: ; preds = %entry
+ br i1 undef, label %bb6, label %bb8
+
+bb6: ; preds = %bb6, %bb5
+ br i1 undef, label %bb8, label %bb6
+
+bb8: ; preds = %bb6, %bb5
+ br label %bb15
+
+bb9: ; preds = %bb15
+ br i1 undef, label %bb10, label %bb11
+
+bb10: ; preds = %bb9
+ unreachable
+
+bb11: ; preds = %bb9
+ %0 = load i32* undef, align 4 ; <i32> [#uses=2]
+ %1 = add i32 %0, 1 ; <i32> [#uses=2]
+ store i32 %1, i32* undef, align 4
+ %2 = load i32* undef, align 4 ; <i32> [#uses=1]
+ store i32 %2, i32* @nn, align 4
+ store i32 0, i32* @al_len, align 4
+ store i32 0, i32* @no_mat, align 4
+ store i32 0, i32* @no_mis, align 4
+ %3 = getelementptr i8* %B, i32 %0 ; <i8*> [#uses=1]
+ tail call arm_apcscc void @diff(i8* undef, i8* %3, i32 undef, i32 undef, i32 undef, i32 undef) nounwind
+ %4 = sitofp i32 undef to double ; <double> [#uses=1]
+ %5 = fdiv double %4, 1.000000e+01 ; <double> [#uses=1]
+ %6 = tail call arm_apcscc i32 (i8*, ...)* @printf(i8* getelementptr ([29 x i8]* @"\01LC12", i32 0, i32 0), double %5) nounwind ; <i32> [#uses=0]
+ %7 = load i32* @al_len, align 4 ; <i32> [#uses=1]
+ %8 = load i32* @no_mat, align 4 ; <i32> [#uses=1]
+ %9 = load i32* @no_mis, align 4 ; <i32> [#uses=1]
+ %10 = sub i32 %7, %8 ; <i32> [#uses=1]
+ %11 = sub i32 %10, %9 ; <i32> [#uses=1]
+ %12 = tail call arm_apcscc i32 (i8*, ...)* @printf(i8* getelementptr ([33 x i8]* @"\01LC16", i32 0, i32 0), i32 %11) nounwind ; <i32> [#uses=0]
+ %13 = tail call arm_apcscc i32 (i8*, ...)* @printf(i8* getelementptr ([47 x i8]* @"\01LC17", i32 0, i32 0), i32 undef, i32 %1, i32 undef, i32 undef) nounwind ; <i32> [#uses=0]
+ br i1 undef, label %bb15, label %bb12
+
+bb12: ; preds = %bb11
+ br label %bb228.i
+
+bb74.i: ; preds = %bb228.i
+ br i1 undef, label %bb138.i, label %bb145.i
+
+bb138.i: ; preds = %bb74.i
+ br label %bb145.i
+
+bb145.i: ; preds = %bb228.i, %bb138.i, %bb74.i
+ br i1 undef, label %bb146.i, label %bb151.i
+
+bb146.i: ; preds = %bb145.i
+ br i1 undef, label %bb228.i, label %bb151.i
+
+bb151.i: ; preds = %bb146.i, %bb145.i
+ br i1 undef, label %bb153.i, label %bb228.i
+
+bb153.i: ; preds = %bb151.i
+ br i1 undef, label %bb220.i, label %bb.nph.i98
+
+bb.nph.i98: ; preds = %bb153.i
+ br label %bb158.i
+
+bb158.i: ; preds = %bb218.i, %bb.nph.i98
+ br i1 undef, label %bb168.i, label %bb160.i
+
+bb160.i: ; preds = %bb158.i
+ br i1 undef, label %bb161.i, label %bb168.i
+
+bb161.i: ; preds = %bb160.i
+ br i1 undef, label %bb168.i, label %bb163.i
+
+bb163.i: ; preds = %bb161.i
+ br i1 undef, label %bb167.i, label %bb168.i
+
+bb167.i: ; preds = %bb163.i
+ br label %bb168.i
+
+bb168.i: ; preds = %bb167.i, %bb163.i, %bb161.i, %bb160.i, %bb158.i
+ br i1 undef, label %bb211.i, label %bb218.i
+
+bb211.i: ; preds = %bb168.i
+ br label %bb218.i
+
+bb218.i: ; preds = %bb211.i, %bb168.i
+ br i1 undef, label %bb220.i, label %bb158.i
+
+bb220.i: ; preds = %bb218.i, %bb153.i
+ br i1 undef, label %bb221.i, label %bb228.i
+
+bb221.i: ; preds = %bb220.i
+ br label %bb228.i
+
+bb228.i: ; preds = %bb221.i, %bb220.i, %bb151.i, %bb146.i, %bb12
+ br i1 undef, label %bb74.i, label %bb145.i
+
+bb15: ; preds = %bb11, %bb8
+ br i1 undef, label %return, label %bb9
+
+return: ; preds = %bb15
+ ret void
+}