Skip to content

Commit

Permalink
17309 ARM backend incorrectly lowers COPY_STRUCT_BYVAL_I32 for thumb1…
Browse files Browse the repository at this point in the history
… targets

This commit implements the correct lowering of the
COPY_STRUCT_BYVAL_I32 pseudo-instruction for thumb1 targets.
Previously, the lowering of COPY_STRUCT_BYVAL_I32 generated the
post-increment forms of ldr/ldrh/ldrb instructions. Thumb1 does not
have the post-increment form of these instructions so the generated
assembly contained invalid instructions.

Passing the generated assembly to gcc caused it to complain with an
error like this:

  Error: cannot honor width suffix -- `ldrb r3,[r0],brson#1'

and the integrated assembler would generate an object file with an
invalid instruction encoding.

This commit contains a small test case that demonstrates the problem
with thumb1 targets as well as an expanded test case that more
throughly tests the lowering of byval struct passing for arm,
thumb1, and thumb2 targets.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192916 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
dmpots committed Oct 17, 2013
1 parent 6483751 commit 7014d27
Show file tree
Hide file tree
Showing 3 changed files with 1,688 additions and 7 deletions.
115 changes: 108 additions & 7 deletions lib/Target/ARM/ARMISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7517,6 +7517,104 @@ class Thumb2StructByvalEmitter : public TargetStructByvalEmitter {
const unsigned UnitStOpc;
};

class Thumb1StructByvalEmitter : public TargetStructByvalEmitter {
public:
Thumb1StructByvalEmitter(const TargetInstrInfo *TII, MachineRegisterInfo &MRI,
unsigned LoadStoreSize)
: TargetStructByvalEmitter(
TII, MRI, (const TargetRegisterClass *)&ARM::tGPRRegClass),
UnitSize(LoadStoreSize),
UnitLdOpc(LoadStoreSize == 4 ? ARM::tLDRi : LoadStoreSize == 2
? ARM::tLDRHi
: LoadStoreSize == 1
? ARM::tLDRBi
: 0),
UnitStOpc(LoadStoreSize == 4 ? ARM::tSTRi : LoadStoreSize == 2
? ARM::tSTRHi
: LoadStoreSize == 1
? ARM::tSTRBi
: 0) {}

void emitAddSubi8(MachineBasicBlock *BB, MachineInstr *MI, DebugLoc &dl,
unsigned opcode, unsigned baseReg, unsigned Imm,
unsigned baseOut) {
MachineInstrBuilder MIB = BuildMI(*BB, MI, dl, TII->get(opcode), baseOut);
MIB = AddDefaultT1CC(MIB);
MIB.addReg(baseReg).addImm(Imm);
AddDefaultPred(MIB);
}

unsigned emitUnitLoad(MachineBasicBlock *BB, MachineInstr *MI, DebugLoc &dl,
unsigned baseReg, unsigned baseOut) {
// load into scratch
unsigned scratch = MRI.createVirtualRegister(TRC);
AddDefaultPred(BuildMI(*BB, MI, dl, TII->get(UnitLdOpc), scratch)
.addReg(baseReg).addImm(0));

// update base pointer
emitAddSubi8(BB, MI, dl, ARM::tADDi8, baseReg, UnitSize, baseOut);
return scratch;
}

void emitUnitStore(MachineBasicBlock *BB, MachineInstr *MI, DebugLoc &dl,
unsigned baseReg, unsigned storeReg, unsigned baseOut) {
// load into scratch
AddDefaultPred(BuildMI(*BB, MI, dl, TII->get(UnitStOpc)).addReg(storeReg)
.addReg(baseReg).addImm(0));

// update base pointer
emitAddSubi8(BB, MI, dl, ARM::tADDi8, baseReg, UnitSize, baseOut);
}

unsigned emitByteLoad(MachineBasicBlock *BB, MachineInstr *MI, DebugLoc &dl,
unsigned baseReg, unsigned baseOut) {
// load into scratch
unsigned scratch = MRI.createVirtualRegister(TRC);
AddDefaultPred(BuildMI(*BB, MI, dl, TII->get(ARM::tLDRBi), scratch)
.addReg(baseReg).addImm(0));

// update base pointer
emitAddSubi8(BB, MI, dl, ARM::tADDi8, baseReg, 1, baseOut);
return scratch;
}

void emitByteStore(MachineBasicBlock *BB, MachineInstr *MI, DebugLoc &dl,
unsigned baseReg, unsigned storeReg, unsigned baseOut) {
// load into scratch
AddDefaultPred(BuildMI(*BB, MI, dl, TII->get(ARM::tSTRBi)).addReg(storeReg)
.addReg(baseReg).addImm(0));

// update base pointer
emitAddSubi8(BB, MI, dl, ARM::tADDi8, baseReg, 1, baseOut);
}

unsigned emitConstantLoad(MachineBasicBlock *BB, MachineInstr *MI,
DebugLoc &dl, unsigned Constant,
const DataLayout *DL) {
unsigned constReg = MRI.createVirtualRegister(TRC);
unsigned Idx = getConstantPoolIndex(BB->getParent(), DL, Constant);
AddDefaultPred(BuildMI(*BB, MI, dl, TII->get(ARM::tLDRpci)).addReg(
constReg, RegState::Define).addConstantPoolIndex(Idx));
return constReg;
}

void emitSubImm(MachineBasicBlock *BB, MachineInstr *MI, DebugLoc &dl,
unsigned InReg, unsigned OutReg) {
emitAddSubi8(BB, MI, dl, ARM::tSUBi8, InReg, UnitSize, OutReg);
}

void emitBranchNE(MachineBasicBlock *BB, MachineInstr *MI, DebugLoc &dl,
MachineBasicBlock *TargetBB) {
BuildMI(*BB, MI, dl, TII->get(ARM::tBcc)).addMBB(TargetBB).addImm(ARMCC::NE)
.addReg(ARM::CPSR);
}

private:
const unsigned UnitSize;
const unsigned UnitLdOpc;
const unsigned UnitStOpc;
};

// This class is a thin wrapper that delegates most of the work to the correct
// TargetStructByvalEmitter implementation. It also handles the lowering for
// targets that support neon because the neon implementation is the same for all
Expand All @@ -7528,13 +7626,16 @@ class StructByvalEmitter {
const DataLayout *DL_)
: UnitSize(LoadStoreSize),
TargetEmitter(
Subtarget->isThumb2()
? static_cast<TargetStructByvalEmitter *>(
new Thumb2StructByvalEmitter(TII_, MRI_,
LoadStoreSize))
: static_cast<TargetStructByvalEmitter *>(
new ARMStructByvalEmitter(TII_, MRI_,
LoadStoreSize))),
Subtarget->isThumb1Only()
? static_cast<TargetStructByvalEmitter *>(
new Thumb1StructByvalEmitter(TII_, MRI_, LoadStoreSize))
: Subtarget->isThumb2()
? static_cast<TargetStructByvalEmitter *>(
new Thumb2StructByvalEmitter(TII_, MRI_,
LoadStoreSize))
: static_cast<TargetStructByvalEmitter *>(
new ARMStructByvalEmitter(TII_, MRI_,
LoadStoreSize))),
TII(TII_), MRI(MRI_), DL(DL_),
VecTRC(UnitSize == 16
? (const TargetRegisterClass *)&ARM::DPairRegClass
Expand Down
Loading

0 comments on commit 7014d27

Please sign in to comment.