Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LowerCallResult regression bugfix #10

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 39 additions & 27 deletions lib/Target/AVR/AVRISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1307,32 +1307,37 @@ SDValue AVRTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
InVals);
}

/// Reverse splitted return values to get the "big endian" format required
/// to agree with the calling convention ABI.
static void ReverseArgumentsToBigEndian(MachineFunction &MF,
SmallVector<CCValAssign, 16> &RVLocs) {
if (RVLocs.size() > 1) {
// Some hackery because SelectionDAGBuilder does not split
// up arguments properly
Type *retType = MF.getFunction().getReturnType();
if (retType->isStructTy()) {
if (retType->getNumContainedTypes() > 1 &&
retType->getNumContainedTypes() > RVLocs.size()) {
for (unsigned i = 0, pos = 0;
i < retType->getNumContainedTypes(); ++i) {
Type *field = retType->getContainedType(i);
if(field->isIntegerTy() && field->getIntegerBitWidth() > 16) {
int Size = field->getIntegerBitWidth() / 16;
std::reverse(RVLocs.begin()+ pos, RVLocs.end() + pos + Size);
pos += Size;
} else {
pos++;
}
/// Reverse splitted return values to "big endian" order
/// so that when registers are assigned from standard CConv
/// we end up with the format required
/// to agree with the avr-gcc calling convention ABI.
/// https://gcc.gnu.org/wiki/avr-gcc
static void ReverseReturnValuePartsToEnsureLittleEndian(
MachineFunction &MF,
SmallVector<CCValAssign, 16> &RVLocs) {

// Some hackery because SelectionDAGBuilder does not split
// up arguments properly
Type *retType = MF.getFunction().getReturnType();
if (retType->isStructTy()) {
// For structs we need more advanced rearrangement.
if (retType->getNumContainedTypes() > 1 &&
retType->getNumContainedTypes() > RVLocs.size()) {
for (unsigned i = 0, pos = 0;
i < retType->getNumContainedTypes(); ++i) {
Type *field = retType->getContainedType(i);
if(field->isIntegerTy() && field->getIntegerBitWidth() > 16) {
int Size = field->getIntegerBitWidth() / 16;
std::reverse(RVLocs.begin()+ pos, RVLocs.end() + pos + Size);
pos += Size;
} else {
pos++;
}
}
} else {
std::reverse(RVLocs.begin(), RVLocs.end());
}
} else {
// For scalar type returns, a simple reversal is fine.
std::reverse(RVLocs.begin(), RVLocs.end());
}
}

Expand All @@ -1353,6 +1358,11 @@ SDValue AVRTargetLowering::LowerCallResult(
auto CCFunction = CCAssignFnForReturn(CallConv);
CCInfo.AnalyzeCallResult(Ins, CCFunction);

if (CallConv != CallingConv::AVR_BUILTIN && RVLocs.size() > 1) {
ReverseReturnValuePartsToEnsureLittleEndian(
DAG.getMachineFunction(), RVLocs);
}

// Copy all of the result registers out of their specified physreg.
for (CCValAssign const &RVLoc : RVLocs) {
Chain = DAG.getCopyFromReg(Chain, dl, RVLoc.getLocReg(), RVLoc.getValVT(),
Expand Down Expand Up @@ -1411,14 +1421,16 @@ AVRTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
// If this is the first return lowered for this function, add the regs to
// the liveout set for the function.
MachineFunction &MF = DAG.getMachineFunction();
unsigned e = RVLocs.size();

// Reverse splitted return values to get the "big endian" format required
// to agree with the calling convention ABI.
ReverseArgumentsToBigEndian(MF, RVLocs);
if (RVLocs.size() > 1) {
// Reverse splitted return values to get the "big endian" format required
// to agree with the calling convention ABI.
ReverseReturnValuePartsToEnsureLittleEndian(MF, RVLocs);
}

SDValue Flag;
SmallVector<SDValue, 4> RetOps(1, Chain);
unsigned e = RVLocs.size();
// Copy the result values into the output registers.
for (unsigned i = 0; i != e; ++i) {
CCValAssign &VA = RVLocs[i];
Expand Down
61 changes: 61 additions & 0 deletions test/CodeGen/AVR/call-avr-rust-issue-130-regression.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
; RUN: llc -O1 < %s -march=avr | FileCheck %s

; CHECK-LABEL: setServoAngle1
define hidden i32 @setServoAngle1(i32) local_unnamed_addr {
entry:
%1 = mul i32 %0, 19
; CHECK: ldi r18, 19
; CHECK: ldi r19, 0
; CHECK: ldi r20, 0
; CHECK: ldi r21, 0
; CHECK: call __mulsi3
; CHECK: ret
ret i32 %1
}

; CHECK-LABEL: setServoAngle2
define hidden i16 @setServoAngle2(i32) local_unnamed_addr {
entry:
%1 = mul i32 %0, 19
; CHECK: ldi r18, 19
; CHECK: ldi r19, 0
; CHECK: ldi r20, 0
; CHECK: ldi r21, 0
; CHECK: call __mulsi3
%2 = trunc i32 %1 to i16
; CHECK: mov r24, r22
; CHECK: mov r25, r23
; CHECK: ret
ret i16 %2
}

; CHECK-LABEL: setServoAngle3
define hidden i32 @setServoAngle3(i32) local_unnamed_addr {
entry:
%1 = call i32 @myExternalFunction1(i32 %0, i32 119)
; CHECK: ldi r18, 119
; CHECK: ldi r19, 0
; CHECK: ldi r20, 0
; CHECK: ldi r21, 0
; CHECK: call myExternalFunction1
; CHECK: ret
ret i32 %1
}

; CHECK-LABEL: setServoAngle4
define hidden i16 @setServoAngle4(i32) local_unnamed_addr {
entry:
%1 = call i32 @myExternalFunction1(i32 %0, i32 119)
; CHECK: ldi r18, 119
; CHECK: ldi r19, 0
; CHECK: ldi r20, 0
; CHECK: ldi r21, 0
; CHECK: call myExternalFunction1
%2 = trunc i32 %1 to i16
; CHECK: mov r24, r22
; CHECK: mov r25, r23
; CHECK: ret
ret i16 %2
}

declare i32 @myExternalFunction1(i32, i32)
26 changes: 13 additions & 13 deletions test/CodeGen/AVR/directmem.ll
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ define i16 @global16_load() {
define void @array16_store() {
; CHECK-LABEL: array16_store:

; CHECK: ldi [[REG1:r[0-9]+]], 221
; CHECK: ldi [[REG2:r[0-9]+]], 170
; CHECK: sts int.array+5, [[REG2]]
; CHECK: sts int.array+4, [[REG1]]

; CHECK: ldi [[REG1:r[0-9]+]], 204
; CHECK: ldi [[REG2:r[0-9]+]], 170
; CHECK: sts int.array+3, [[REG2]]
Expand All @@ -94,11 +99,6 @@ define void @array16_store() {
; CHECK: sts int.array+1, [[REG2]]
; CHECK: sts int.array, [[REG1]]


; CHECK: ldi [[REG1:r[0-9]+]], 221
; CHECK: ldi [[REG2:r[0-9]+]], 170
; CHECK: sts int.array+5, [[REG2]]
; CHECK: sts int.array+4, [[REG1]]
store i16 43707, i16* getelementptr inbounds ([3 x i16], [3 x i16]* @int.array, i32 0, i64 0)
store i16 43724, i16* getelementptr inbounds ([3 x i16], [3 x i16]* @int.array, i32 0, i64 1)
store i16 43741, i16* getelementptr inbounds ([3 x i16], [3 x i16]* @int.array, i32 0, i64 2)
Expand Down Expand Up @@ -152,6 +152,14 @@ define i32 @global32_load() {

define void @array32_store() {
; CHECK-LABEL: array32_store:
; CHECK: ldi [[REG1:r[0-9]+]], 170
; CHECK: ldi [[REG2:r[0-9]+]], 153
; CHECK: sts long.array+11, [[REG2]]
; CHECK: sts long.array+10, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 204
; CHECK: ldi [[REG2:r[0-9]+]], 187
; CHECK: sts long.array+9, [[REG2]]
; CHECK: sts long.array+8, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 102
; CHECK: ldi [[REG2:r[0-9]+]], 85
; CHECK: sts long.array+7, [[REG2]]
Expand All @@ -168,14 +176,6 @@ define void @array32_store() {
; CHECK: ldi [[REG2:r[0-9]+]], 13
; CHECK: sts long.array+1, [[REG2]]
; CHECK: sts long.array, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 170
; CHECK: ldi [[REG2:r[0-9]+]], 153
; CHECK: sts long.array+11, [[REG2]]
; CHECK: sts long.array+10, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 204
; CHECK: ldi [[REG2:r[0-9]+]], 187
; CHECK: sts long.array+9, [[REG2]]
; CHECK: sts long.array+8, [[REG1]]
store i32 2887454020, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @long.array, i32 0, i64 0)
store i32 1432778632, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @long.array, i32 0, i64 1)
store i32 2578103244, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @long.array, i32 0, i64 2)
Expand Down