mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
17309 ARM backend incorrectly lowers COPY_STRUCT_BYVAL_I32 for thumb1 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],#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
This commit is contained in:
parent
6483751a36
commit
7014d274e4
@ -7517,6 +7517,104 @@ private:
|
||||
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
|
||||
@ -7528,13 +7626,16 @@ public:
|
||||
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
|
||||
|
1523
test/CodeGen/ARM/struct_byval_arm_t1_t2.ll
Normal file
1523
test/CodeGen/ARM/struct_byval_arm_t1_t2.ll
Normal file
File diff suppressed because it is too large
Load Diff
57
test/CodeGen/Thumb/PR17309.ll
Normal file
57
test/CodeGen/Thumb/PR17309.ll
Normal file
@ -0,0 +1,57 @@
|
||||
; RUN: llc -mtriple thumbv5-none-linux-gnueabi < %s | FileCheck %s
|
||||
|
||||
%struct.C = type { [1000 x i8] }
|
||||
%struct.S = type { [1000 x i16] }
|
||||
%struct.I = type { [1000 x i32] }
|
||||
|
||||
;CHECK-LABEL: pass_C:
|
||||
;CHECK-NOT: ldrb r{{[0-9]+}}, [{{.*}}], #1
|
||||
;CHECK-NOT: strb r{{[0-9]+}}, [{{.*}}], #1
|
||||
define void @pass_C() #0 {
|
||||
entry:
|
||||
%c = alloca %struct.C, align 1
|
||||
%0 = getelementptr inbounds %struct.C* %c, i32 0, i32 0, i32 0
|
||||
call void @llvm.lifetime.start(i64 1000, i8* %0) #1
|
||||
call void @use_C(%struct.C* byval %c) #3
|
||||
call void @llvm.lifetime.end(i64 1000, i8* %0) #1
|
||||
ret void
|
||||
}
|
||||
|
||||
;CHECK-LABEL: pass_S:
|
||||
;CHECK-NOT: ldrh r{{[0-9]+}}, [{{.*}}], #2
|
||||
;CHECK-NOT: strh r{{[0-9]+}}, [{{.*}}], #2
|
||||
define void @pass_S() #0 {
|
||||
entry:
|
||||
%s = alloca %struct.S, align 2
|
||||
%0 = bitcast %struct.S* %s to i8*
|
||||
call void @llvm.lifetime.start(i64 2000, i8* %0) #1
|
||||
call void @use_S(%struct.S* byval %s) #3
|
||||
call void @llvm.lifetime.end(i64 2000, i8* %0) #1
|
||||
ret void
|
||||
}
|
||||
|
||||
;CHECK-LABEL: pass_I:
|
||||
;CHECK-NOT: ldr r{{[0-9]+}}, [{{.*}}], #4
|
||||
;CHECK-NOT: str r{{[0-9]+}}, [{{.*}}], #4
|
||||
define void @pass_I() #0 {
|
||||
entry:
|
||||
%i = alloca %struct.I, align 4
|
||||
%0 = bitcast %struct.I* %i to i8*
|
||||
call void @llvm.lifetime.start(i64 4000, i8* %0) #1
|
||||
call void @use_I(%struct.I* byval %i) #3
|
||||
call void @llvm.lifetime.end(i64 4000, i8* %0) #1
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @use_C(%struct.C* byval) #2
|
||||
declare void @use_S(%struct.S* byval) #2
|
||||
declare void @use_I(%struct.I* byval) #2
|
||||
|
||||
declare void @llvm.lifetime.start(i64, i8* nocapture) #1
|
||||
declare void @llvm.lifetime.end(i64, i8* nocapture) #1
|
||||
|
||||
|
||||
attributes #0 = { nounwind optsize "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #1 = { nounwind }
|
||||
attributes #2 = { optsize "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #3 = { nounwind optsize }
|
Loading…
Reference in New Issue
Block a user