From 085701b8b0084b24b6badff7440ba63ea90e112e Mon Sep 17 00:00:00 2001 From: Ikhlas Ajbar Date: Mon, 22 Jun 2020 16:03:22 -0500 Subject: [PATCH] [Hexagon] Reducing minimum alignment requirement This patch reduces minimum alignment requirement to 1 byte for arguments passed by value on stack. --- llvm/lib/Target/Hexagon/HexagonCallingConv.td | 32 ++++++++++++++++- llvm/lib/Target/Hexagon/HexagonISelLowering.cpp | 9 +++++ llvm/test/CodeGen/Hexagon/abi-padding-2.ll | 45 ++++++++++++++++++++++++ llvm/test/CodeGen/Hexagon/abi-padding.ll | 46 +++++++++++++++++++++++++ 4 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/Hexagon/abi-padding-2.ll create mode 100644 llvm/test/CodeGen/Hexagon/abi-padding.ll diff --git a/llvm/lib/Target/Hexagon/HexagonCallingConv.td b/llvm/lib/Target/Hexagon/HexagonCallingConv.td index 5c31a81..93e17e6 100644 --- a/llvm/lib/Target/Hexagon/HexagonCallingConv.td +++ b/llvm/lib/Target/Hexagon/HexagonCallingConv.td @@ -18,7 +18,7 @@ def CC_HexagonStack: CallingConv<[ CCAssignToStack<8,8>> ]>; -def CC_Hexagon: CallingConv<[ +def CC_Hexagon_Legacy: CallingConv<[ CCIfType<[i1,i8,i16], CCPromoteToType>, CCIfType<[f32], @@ -48,6 +48,36 @@ def CC_Hexagon: CallingConv<[ CCDelegateTo ]>; +def CC_Hexagon: CallingConv<[ + CCIfType<[i1,i8,i16], + CCPromoteToType>, + CCIfType<[f32], + CCBitConvertToType>, + CCIfType<[f64], + CCBitConvertToType>, + + CCIfByVal< + CCPassByVal<8,1>>, + CCIfArgIsVarArg< + CCDelegateTo>, + + // Pass split values in pairs, allocate odd register if necessary. + CCIfType<[i32], + CCIfSplit< + CCCustom<"CC_SkipOdd">>>, + + CCIfType<[i32,v2i16,v4i8], + CCAssignToReg<[R0,R1,R2,R3,R4,R5]>>, + // Make sure to allocate any skipped 32-bit register, so it does not get + // allocated to a subsequent 32-bit value. + CCIfType<[i64,v2i32,v4i16,v8i8], + CCCustom<"CC_SkipOdd">>, + CCIfType<[i64,v2i32,v4i16,v8i8], + CCAssignToReg<[D0,D1,D2]>>, + + CCDelegateTo +]>; + def RetCC_Hexagon: CallingConv<[ CCIfType<[i1,i8,i16], CCPromoteToType>, diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp index 99d70a0..333561f 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp +++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp @@ -109,6 +109,11 @@ static cl::opt AlignLoads("hexagon-align-loads", cl::Hidden, cl::init(false), cl::desc("Rewrite unaligned loads as a pair of aligned loads")); +static cl::opt + DisableArgsMinAlignment("hexagon-disable-args-min-alignment", cl::Hidden, + cl::init(false), + cl::desc("Disable minimum alignment of 1 for " + "arguments passed by value on stack")); namespace { @@ -401,6 +406,8 @@ HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, if (Subtarget.useHVXOps()) CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon_HVX); + else if (DisableArgsMinAlignment) + CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon_Legacy); else CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon); @@ -762,6 +769,8 @@ SDValue HexagonTargetLowering::LowerFormalArguments( if (Subtarget.useHVXOps()) CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon_HVX); + else if (DisableArgsMinAlignment) + CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon_Legacy); else CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon); diff --git a/llvm/test/CodeGen/Hexagon/abi-padding-2.ll b/llvm/test/CodeGen/Hexagon/abi-padding-2.ll new file mode 100644 index 0000000..4bda4ae --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/abi-padding-2.ll @@ -0,0 +1,45 @@ +; RUN: llc -march=hexagon -mcpu=hexagonv65 < %s | FileCheck %s +; REQUIRES: hexagon + +; C file was: +; struct S { char b; long long a; }; +; void foo(int x, struct S arg1); +; void bar() { +; struct S s; +; s.b = 'a'; +; foo(42, s); +;} + +; +; Test that while passing a 7-byte struct on the stack, the +; size of the struct is 16 bytes including padding since its +; largest member is of type long long. This was being handled +; correctly but is a sanity check against any potential future +; regressions. +; + +; CHECK: memd(r{{[0-9]+}}+#8) = +; CHECK: memd(r{{[0-9]+}}+#0) = + +%struct.S = type { i8, i64 } + +; Function Attrs: nounwind +define dso_local void @bar() local_unnamed_addr #0 { +entry: + %s = alloca %struct.S, align 8 + %0 = getelementptr inbounds %struct.S, %struct.S* %s, i32 0, i32 0 + call void @llvm.lifetime.start.p0i8(i64 16, i8* nonnull %0) #3 + store i8 97, i8* %0, align 8 + tail call void @foo(i32 42, %struct.S* nonnull byval(%struct.S) align 8 %s) #3 + call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %0) #3 + ret void +} + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +declare dso_local void @foo(i32, %struct.S* byval(%struct.S) align 8) local_unnamed_addr #2 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + diff --git a/llvm/test/CodeGen/Hexagon/abi-padding.ll b/llvm/test/CodeGen/Hexagon/abi-padding.ll new file mode 100644 index 0000000..ee2b990 --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/abi-padding.ll @@ -0,0 +1,46 @@ +; RUN: llc -march=hexagon -mcpu=hexagonv65 < %s | FileCheck %s +; REQUIRES: hexagon + +; C file was: +; struct S { int a[3];}; +; void foo(int x, struct S arg1, struct S arg2); +; void bar() { +; struct S s; +; s.a[0] = 9; +; foo(42, s, s); +; } + +; Test that while passing a 12-byte struct on the stack, the +; struct is aligned to 4 bytes since its largest member is of type int. +; Previously, the struct was being aligned to 8 bytes + +; CHECK: memw(r{{[0-9]+}}+#12) = #9 + +; Check that the flag hexagon-disable-args-min-alignment works and the struct +; is aligned to 8 bytes. +; RUN: llc -march=hexagon -mcpu=hexagonv65 -hexagon-disable-args-min-alignment < %s | FileCheck -check-prefix=HEXAGON_LEGACY %s + +; HEXAGON_LEGACY: memw(r{{[0-9]+}}+#16) = #9 + +%struct.S = type { [3 x i32] } + +; Function Attrs: nounwind +define dso_local void @bar() local_unnamed_addr #0 { +entry: + %s = alloca %struct.S, align 4 + %0 = bitcast %struct.S* %s to i8* + call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %0) #3 + %arrayidx = getelementptr inbounds %struct.S, %struct.S* %s, i32 0, i32 0, i32 0 + store i32 9, i32* %arrayidx, align 4 + tail call void @foo(i32 42, %struct.S* nonnull byval(%struct.S) align 4 %s, %struct.S* nonnull byval(%struct.S) align 4 %s) #3 + call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %0) #3 + ret void +} + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +declare dso_local void @foo(i32, %struct.S* byval(%struct.S) align 4, %struct.S* byval(%struct.S) align 4) local_unnamed_addr #2 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 -- 2.7.4