mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01:00
RTABI chapter 4.3.4 specifies __eabi_mem* calls. Specifically, __eabi_memset accepts parameters (ptr, size, value) in a different order than GNU's memset (ptr, value, size), therefore the special lowering in AAPCS mode. Implementation by Evzen Muller.
llvm-svn: 131868
This commit is contained in:
parent
a4187a96c9
commit
759db3cbe3
@ -396,6 +396,12 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
|
||||
setLibcallCallingConv(RTLIB::UDIV_I8, CallingConv::ARM_AAPCS);
|
||||
setLibcallCallingConv(RTLIB::UDIV_I16, CallingConv::ARM_AAPCS);
|
||||
setLibcallCallingConv(RTLIB::UDIV_I32, CallingConv::ARM_AAPCS);
|
||||
|
||||
// Memory operations
|
||||
// RTABI chapter 4.3.4
|
||||
setLibcallName(RTLIB::MEMCPY, "__aeabi_memcpy");
|
||||
setLibcallName(RTLIB::MEMMOVE, "__aeabi_memmove");
|
||||
setLibcallName(RTLIB::MEMSET, "__aeabi_memset");
|
||||
}
|
||||
|
||||
if (Subtarget->isThumb1Only())
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
#define DEBUG_TYPE "arm-selectiondag-info"
|
||||
#include "ARMTargetMachine.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
using namespace llvm;
|
||||
|
||||
ARMSelectionDAGInfo::ARMSelectionDAGInfo(const TargetMachine &TM)
|
||||
@ -132,3 +134,65 @@ ARMSelectionDAGInfo::EmitTargetCodeForMemcpy(SelectionDAG &DAG, DebugLoc dl,
|
||||
}
|
||||
return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &TFOps[0], i);
|
||||
}
|
||||
|
||||
// Adjust parameters for memset, EABI uses format (ptr, size, value),
|
||||
// GNU library uses (ptr, value, size)
|
||||
// See RTABI section 4.3.4
|
||||
SDValue
|
||||
ARMSelectionDAGInfo::EmitTargetCodeForMemset(SelectionDAG &DAG, DebugLoc dl,
|
||||
SDValue Chain, SDValue Dst,
|
||||
SDValue Src, SDValue Size,
|
||||
unsigned Align, bool isVolatile,
|
||||
MachinePointerInfo DstPtrInfo) const
|
||||
{
|
||||
// Use default for non AAPCS subtargets
|
||||
if (!Subtarget->isAAPCS_ABI())
|
||||
return SDValue();
|
||||
|
||||
const ARMTargetLowering &TLI =
|
||||
*static_cast<const ARMTargetLowering*>(DAG.getTarget().getTargetLowering());
|
||||
TargetLowering::ArgListTy Args;
|
||||
TargetLowering::ArgListEntry Entry;
|
||||
|
||||
// First argument: data pointer
|
||||
const Type *IntPtrTy = TLI.getTargetData()->getIntPtrType(*DAG.getContext());
|
||||
Entry.Node = Dst;
|
||||
Entry.Ty = IntPtrTy;
|
||||
Args.push_back(Entry);
|
||||
|
||||
// Second argument: buffer size
|
||||
Entry.Node = Size;
|
||||
Entry.Ty = IntPtrTy;
|
||||
Entry.isSExt = false;
|
||||
Args.push_back(Entry);
|
||||
|
||||
// Extend or truncate the argument to be an i32 value for the call.
|
||||
if (Src.getValueType().bitsGT(MVT::i32))
|
||||
Src = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src);
|
||||
else
|
||||
Src = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, Src);
|
||||
|
||||
// Third argument: value to fill
|
||||
Entry.Node = Src;
|
||||
Entry.Ty = Type::getInt32Ty(*DAG.getContext());
|
||||
Entry.isSExt = true;
|
||||
Args.push_back(Entry);
|
||||
|
||||
// Emit __eabi_memset call
|
||||
std::pair<SDValue,SDValue> CallResult =
|
||||
TLI.LowerCallTo(Chain,
|
||||
Type::getVoidTy(*DAG.getContext()), // return type
|
||||
false, // return sign ext
|
||||
false, // return zero ext
|
||||
false, // is var arg
|
||||
false, // is in regs
|
||||
0, // number of fixed arguments
|
||||
TLI.getLibcallCallingConv(RTLIB::MEMSET), // call conv
|
||||
false, // is tail call
|
||||
false, // is return val used
|
||||
DAG.getExternalSymbol(TLI.getLibcallName(RTLIB::MEMSET),
|
||||
TLI.getPointerTy()), // callee
|
||||
Args, DAG, dl); // arg list, DAG and debug
|
||||
|
||||
return CallResult.second;
|
||||
}
|
||||
|
@ -35,6 +35,15 @@ public:
|
||||
bool isVolatile, bool AlwaysInline,
|
||||
MachinePointerInfo DstPtrInfo,
|
||||
MachinePointerInfo SrcPtrInfo) const;
|
||||
|
||||
// Adjust parameters for memset, see RTABI section 4.3.4
|
||||
virtual
|
||||
SDValue EmitTargetCodeForMemset(SelectionDAG &DAG, DebugLoc dl,
|
||||
SDValue Chain,
|
||||
SDValue Op1, SDValue Op2,
|
||||
SDValue Op3, unsigned Align,
|
||||
bool isVolatile,
|
||||
MachinePointerInfo DstPtrInfo) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,26 @@
|
||||
; RUN: llc < %s -march=arm
|
||||
; RUN: llc < %s -march=arm -o - | FileCheck %s
|
||||
; RUN: llc < %s -mtriple=arm-none-eabi -o - | FileCheck --check-prefix=EABI %s
|
||||
|
||||
@from = common global [500 x i32] zeroinitializer, align 4
|
||||
@to = common global [500 x i32] zeroinitializer, align 4
|
||||
|
||||
define void @f() {
|
||||
entry:
|
||||
call void @llvm.memmove.i32( i8* null, i8* null, i32 64, i32 0 )
|
||||
call void @llvm.memcpy.i32( i8* null, i8* null, i32 64, i32 0 )
|
||||
call void @llvm.memset.i32( i8* null, i8 64, i32 0, i32 0 )
|
||||
|
||||
; CHECK: memmove
|
||||
; EABI: __aeabi_memmove
|
||||
call void @llvm.memmove.i32( i8* bitcast ([500 x i32]* @from to i8*), i8* bitcast ([500 x i32]* @to to i8*), i32 500, i32 0 )
|
||||
|
||||
; CHECK: memcpy
|
||||
; EABI: __aeabi_memcpy
|
||||
call void @llvm.memcpy.i32( i8* bitcast ([500 x i32]* @from to i8*), i8* bitcast ([500 x i32]* @to to i8*), i32 500, i32 0 )
|
||||
|
||||
; EABI memset swaps arguments
|
||||
; CHECK: mov r1, #0
|
||||
; CHECK: memset
|
||||
; EABI: mov r2, #0
|
||||
; EABI: __aeabi_memset
|
||||
call void @llvm.memset.i32( i8* bitcast ([500 x i32]* @from to i8*), i8 0, i32 500, i32 0 )
|
||||
unreachable
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user