mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-03 01:12:53 +00:00
Initial support for some Thumb2 instructions.
Patch by Viktor Kutuzov and Anton Korzh from Access Softek, Inc. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@73622 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e3a6165423
commit
52237119a9
@ -52,8 +52,13 @@ public:
|
||||
|
||||
virtual const char *getPassName() const {
|
||||
return "ARM Instruction Selection";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// getI32Imm - Return a target constant with the specified value, of type i32.
|
||||
inline SDValue getI32Imm(unsigned Imm) {
|
||||
return CurDAG->getTargetConstant(Imm, MVT::i32);
|
||||
}
|
||||
|
||||
SDNode *Select(SDValue Op);
|
||||
virtual void InstructionSelect();
|
||||
bool SelectAddrMode2(SDValue Op, SDValue N, SDValue &Base,
|
||||
@ -84,6 +89,9 @@ public:
|
||||
bool SelectThumbAddrModeSP(SDValue Op, SDValue N, SDValue &Base,
|
||||
SDValue &OffImm);
|
||||
|
||||
bool SelectShifterOperand(SDValue Op, SDValue N,
|
||||
SDValue &BaseReg, SDValue &Opc);
|
||||
|
||||
bool SelectShifterOperandReg(SDValue Op, SDValue N, SDValue &A,
|
||||
SDValue &B, SDValue &C);
|
||||
|
||||
@ -509,8 +517,30 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue Op, SDValue N,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ARMDAGToDAGISel::SelectShifterOperand(SDValue Op,
|
||||
SDValue N,
|
||||
SDValue &BaseReg,
|
||||
SDValue &Opc) {
|
||||
ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N);
|
||||
|
||||
// Don't match base register only case. That is matched to a separate
|
||||
// lower complexity pattern with explicit register operand.
|
||||
if (ShOpcVal == ARM_AM::no_shift) return false;
|
||||
|
||||
BaseReg = N.getOperand(0);
|
||||
unsigned ShImmVal = 0;
|
||||
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1)))
|
||||
ShImmVal = RHS->getZExtValue() & 31;
|
||||
else
|
||||
return false;
|
||||
|
||||
Opc = getI32Imm(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ARMDAGToDAGISel::SelectShifterOperandReg(SDValue Op,
|
||||
SDValue N,
|
||||
SDValue N,
|
||||
SDValue &BaseReg,
|
||||
SDValue &ShReg,
|
||||
SDValue &Opc) {
|
||||
@ -549,6 +579,10 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
||||
switch (N->getOpcode()) {
|
||||
default: break;
|
||||
case ISD::Constant: {
|
||||
// ARMv6T2 and later should materialize imms via MOV / MOVT pair.
|
||||
if (Subtarget->hasV6T2Ops() || Subtarget->hasThumb2())
|
||||
break;
|
||||
|
||||
unsigned Val = cast<ConstantSDNode>(N)->getZExtValue();
|
||||
bool UseCP = true;
|
||||
if (Subtarget->isThumb())
|
||||
|
@ -1384,6 +1384,12 @@ def : ARMV5TEPat<(add GPR:$acc,
|
||||
|
||||
include "ARMInstrThumb.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Thumb2 Support
|
||||
//
|
||||
|
||||
include "ARMInstrThumb2.td"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Floating Point Support
|
||||
//
|
||||
|
@ -10,3 +10,199 @@
|
||||
// This file describes the Thumb2 instruction set.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Shifted operands. No register controlled shifts for Thumb2.
|
||||
// Note: We do not support rrx shifted operands yet.
|
||||
def t2_so_reg : Operand<i32>, // reg imm
|
||||
ComplexPattern<i32, 2, "SelectShifterOperand",
|
||||
[shl,srl,sra,rotr]> {
|
||||
let PrintMethod = "printSOOperand";
|
||||
let MIOperandInfo = (ops GPR, i32imm);
|
||||
}
|
||||
|
||||
def LO16 : SDNodeXForm<imm, [{
|
||||
// Transformation function: shift the immediate value down into the low bits.
|
||||
return getI32Imm((unsigned short)N->getZExtValue());
|
||||
}]>;
|
||||
|
||||
def HI16 : SDNodeXForm<imm, [{
|
||||
// Transformation function: shift the immediate value down into the low bits.
|
||||
return getI32Imm((unsigned)N->getZExtValue() >> 16);
|
||||
}]>;
|
||||
|
||||
def imm16high : PatLeaf<(i32 imm), [{
|
||||
// Returns true if all bits out of the [31..16] range are 0.
|
||||
return ((N->getZExtValue() & 0xFFFF0000ULL) == N->getZExtValue());
|
||||
}], HI16>;
|
||||
|
||||
def imm16high0xffff : PatLeaf<(i32 imm), [{
|
||||
// Returns true if lo 16 bits are set and this is a 32-bit value.
|
||||
return ((N->getZExtValue() & 0x0000FFFFULL) == 0xFFFFULL);
|
||||
}], HI16>;
|
||||
|
||||
def imm0_4095 : PatLeaf<(i32 imm), [{
|
||||
return (uint32_t)N->getZExtValue() < 4096;
|
||||
}]>;
|
||||
|
||||
def imm0_4095_neg : PatLeaf<(i32 imm), [{
|
||||
return (uint32_t)-N->getZExtValue() < 4096;
|
||||
}], imm_neg_XFORM>;
|
||||
|
||||
def imm0_65535 : PatLeaf<(i32 imm), [{
|
||||
return N->getZExtValue() < 65536;
|
||||
}]>;
|
||||
|
||||
// A6.3.2 Modified immediate constants in Thumb instructions (#<const>)
|
||||
// FIXME: Move it the the addrmode matcher code.
|
||||
def t2_so_imm : PatLeaf<(i32 imm), [{
|
||||
uint64_t v = N->getZExtValue();
|
||||
if (v == 0 || v > 0xffffffffUL) return false;
|
||||
// variant1 - 0b0000x - 8-bit which could be zero (not supported for now)
|
||||
|
||||
// variant2 - 0b00nnx - 8-bit repeated inside the 32-bit room
|
||||
unsigned hi16 = (unsigned)(v >> 16);
|
||||
unsigned lo16 = (unsigned)(v & 0xffffUL);
|
||||
bool valid = (hi16 == lo16) && (
|
||||
(v & 0x00ff00ffUL) == 0 || // type 0001x
|
||||
(v & 0xff00ff00UL) == 0 || // type 0010x
|
||||
((lo16 >> 8) == (lo16 & 0xff))); // type 0011x
|
||||
if (valid) return true;
|
||||
|
||||
// variant3 - 0b01000..0b11111 - 8-bit shifted inside the 32-bit room
|
||||
unsigned shift = CountLeadingZeros_32(v);
|
||||
uint64_t mask = (0xff000000ULL >> shift);
|
||||
// If valid, it is type 01000 + shift
|
||||
return ((shift < 24) && (v & mask) > 0) && ((v & (~mask)) == 0);
|
||||
}]>;
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Thumb-2 to cover the functionality of the ARM instruction set.
|
||||
//
|
||||
|
||||
/// T2I_bin_irs - Defines a set of (op reg, {so_imm|reg|so_reg}) patterns for a
|
||||
// binary operation that produces a value.
|
||||
multiclass T2I_bin_irs<string opc, PatFrag opnode> {
|
||||
// shifted imm
|
||||
def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
|
||||
!strconcat(opc, " $dst, $lhs, $rhs"),
|
||||
[(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
// register
|
||||
def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
|
||||
!strconcat(opc, " $dst, $lhs, $rhs"),
|
||||
[(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
// shifted register
|
||||
def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
|
||||
!strconcat(opc, " $dst, $lhs, $rhs"),
|
||||
[(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
}
|
||||
|
||||
/// T2I_bin_s_irs - Similar to T2I_bin_irs except it sets the 's' bit so the
|
||||
/// instruction modifies the CPSR register.
|
||||
let Defs = [CPSR] in {
|
||||
multiclass T2I_bin_s_irs<string opc, PatFrag opnode> {
|
||||
// shifted imm
|
||||
def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
|
||||
!strconcat(opc, "s $dst, $lhs, $rhs"),
|
||||
[(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
|
||||
// register
|
||||
def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
|
||||
!strconcat(opc, "s $dst, $lhs, $rhs"),
|
||||
[(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
|
||||
// shifted register
|
||||
def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
|
||||
!strconcat(opc, "s $dst, $lhs, $rhs"),
|
||||
[(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
}
|
||||
}
|
||||
|
||||
/// T2I_bin_c_irs - Similar to T2I_bin_irs except it uses the 's' bit. Also the
|
||||
/// instruction can optionally set the CPSR register.
|
||||
let Uses = [CPSR] in {
|
||||
multiclass T2I_bin_c_irs<string opc, PatFrag opnode> {
|
||||
// shifted imm
|
||||
def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs, cc_out:$s),
|
||||
!strconcat(opc, "${s} $dst, $lhs, $rhs"),
|
||||
[(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
|
||||
// register
|
||||
def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs, cc_out:$s),
|
||||
!strconcat(opc, "${s} $dst, $lhs, $rhs"),
|
||||
[(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
|
||||
// shifted register
|
||||
def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs, cc_out:$s),
|
||||
!strconcat(opc, "${s} $dst, $lhs, $rhs"),
|
||||
[(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Arithmetic Instructions.
|
||||
//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Move Instructions.
|
||||
//
|
||||
def tMOVi16 : PseudoInst<(outs GPR:$dst), (ins i32imm:$src),
|
||||
"mov $dst, $src",
|
||||
[(set GPR:$dst, imm0_65535:$src)]>,
|
||||
Requires<[HasThumb2]>;
|
||||
|
||||
let isTwoAddress = 1 in
|
||||
def tMOVTi16 : PseudoInst<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm),
|
||||
"movt $dst, $imm",
|
||||
[(set GPR:$dst, (or (and GPR:$src, 0xffff),
|
||||
imm16high:$imm))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
|
||||
def : Pat<(and (or GPR:$src, imm16high:$imm1), imm16high0xffff:$imm2),
|
||||
(tMOVTi16 GPR:$src, (HI16 imm16high:$imm1))>,
|
||||
Requires<[HasThumb2]>;
|
||||
|
||||
def : Pat<(i32 imm:$imm),
|
||||
(tMOVTi16 (tMOVi16 (LO16 imm:$imm)),(HI16 imm:$imm))>,
|
||||
Requires<[HasThumb2]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Arithmetic Instructions.
|
||||
//
|
||||
defm t2ADD : T2I_bin_irs <"add", BinOpFrag<(add node:$LHS, node:$RHS)>>;
|
||||
defm t2SUB : T2I_bin_irs <"sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>;
|
||||
|
||||
def tADDri12 : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
|
||||
"add $dst, $lhs, $rhs",
|
||||
[(set GPR:$dst, (add GPR:$lhs, imm0_4095:$rhs))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
def tSUBri12 : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
|
||||
"sub $dst, $lhs, $rhs",
|
||||
[(set GPR:$dst, (add GPR:$lhs, imm0_4095_neg:$rhs))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
|
||||
defm t2ADDS : T2I_bin_s_irs<"add", BinOpFrag<(addc node:$LHS, node:$RHS)>>;
|
||||
defm t2SUBS : T2I_bin_s_irs<"sub", BinOpFrag<(subc node:$LHS, node:$RHS)>>;
|
||||
|
||||
defm t2ADC : T2I_bin_c_irs<"adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>;
|
||||
defm t2SBC : T2I_bin_c_irs<"sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>;
|
||||
|
||||
|
||||
def tMLS : PseudoInst<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
|
||||
"mls $dst, $a, $b, $c",
|
||||
[(set GPR:$dst, (sub GPR:$c, (mul GPR:$a, GPR:$b)))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
|
||||
def tORNrs : PseudoInst<(outs GPR:$dst), (ins GPR:$src1, t2_so_reg:$src2),
|
||||
"orn $dst, $src1, $src2",
|
||||
[(set GPR:$dst, (or GPR:$src1, (not t2_so_reg: $src2)))]>,
|
||||
Requires<[HasThumb2]>;
|
||||
|
@ -97,6 +97,7 @@ namespace {
|
||||
const char *Modifier = 0);
|
||||
void printSOImmOperand(const MachineInstr *MI, int opNum);
|
||||
void printSOImm2PartOperand(const MachineInstr *MI, int opNum);
|
||||
void printSOOperand(const MachineInstr *MI, int OpNum);
|
||||
void printSORegOperand(const MachineInstr *MI, int opNum);
|
||||
void printAddrMode2Operand(const MachineInstr *MI, int OpNo);
|
||||
void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNo);
|
||||
@ -396,6 +397,28 @@ void ARMAsmPrinter::printSOImm2PartOperand(const MachineInstr *MI, int OpNum) {
|
||||
printSOImm(O, ARM_AM::getSOImmVal(V2), VerboseAsm, TAI);
|
||||
}
|
||||
|
||||
// Constant shifts so_reg is a 3-operand unit corresponding to register forms of
|
||||
// the A5.1 "Addressing Mode 1 - Data-processing operands" forms. This
|
||||
// includes:
|
||||
// REG 0 - e.g. R5
|
||||
// REG IMM, SH_OPC - e.g. R5, LSL #3
|
||||
void ARMAsmPrinter::printSOOperand(const MachineInstr *MI, int OpNum) {
|
||||
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
||||
const MachineOperand &MO2 = MI->getOperand(OpNum+1);
|
||||
|
||||
unsigned Reg = MO1.getReg();
|
||||
assert(TargetRegisterInfo::isPhysicalRegister(Reg));
|
||||
O << TM.getRegisterInfo()->getAsmName(Reg);
|
||||
|
||||
// Print the shift opc.
|
||||
O << ", "
|
||||
<< ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm()))
|
||||
<< " ";
|
||||
|
||||
assert(MO2.isImm() && "Not a valid t2_so_reg value!");
|
||||
O << "#" << ARM_AM::getSORegOffset(MO2.getImm());
|
||||
}
|
||||
|
||||
// so_reg is a 4-operand unit corresponding to register forms of the A5.1
|
||||
// "Addressing Mode 1 - Data-processing operands" forms. This includes:
|
||||
// REG 0 0 - e.g. R5
|
||||
|
50
test/CodeGen/ARM/thumb2-add.ll
Normal file
50
test/CodeGen/ARM/thumb2-add.ll
Normal file
@ -0,0 +1,50 @@
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep add | grep #255
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep add | grep #256
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep add | grep #257
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep add | grep #4094
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep add | grep #4095
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep add | grep #4096
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep add
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep add | grep lsl | grep #8
|
||||
|
||||
define i32 @t2ADDrc_255(i32 %lhs) {
|
||||
%Rd = add i32 %lhs, 255;
|
||||
ret i32 %Rd
|
||||
}
|
||||
|
||||
define i32 @t2ADDrc_256(i32 %lhs) {
|
||||
%Rd = add i32 %lhs, 256;
|
||||
ret i32 %Rd
|
||||
}
|
||||
|
||||
define i32 @t2ADDrc_257(i32 %lhs) {
|
||||
%Rd = add i32 %lhs, 257;
|
||||
ret i32 %Rd
|
||||
}
|
||||
|
||||
define i32 @t2ADDrc_4094(i32 %lhs) {
|
||||
%Rd = add i32 %lhs, 4094;
|
||||
ret i32 %Rd
|
||||
}
|
||||
|
||||
define i32 @t2ADDrc_4095(i32 %lhs) {
|
||||
%Rd = add i32 %lhs, 4095;
|
||||
ret i32 %Rd
|
||||
}
|
||||
|
||||
define i32 @t2ADDrc_4096(i32 %lhs) {
|
||||
%Rd = add i32 %lhs, 4096;
|
||||
ret i32 %Rd
|
||||
}
|
||||
|
||||
define i32 @t2ADDrr(i32 %lhs, i32 %rhs) {
|
||||
%Rd = add i32 %lhs, %rhs;
|
||||
ret i32 %Rd
|
||||
}
|
||||
|
||||
define i32 @t2ADDrs(i32 %lhs, i32 %rhs) {
|
||||
%tmp = shl i32 %rhs, 8
|
||||
%Rd = add i32 %lhs, %tmp;
|
||||
ret i32 %Rd
|
||||
}
|
||||
|
127
test/CodeGen/ARM/thumb2-mov.ll
Normal file
127
test/CodeGen/ARM/thumb2-mov.ll
Normal file
@ -0,0 +1,127 @@
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep #11206827
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep #2868947712
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep #2880154539
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep #251658240
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep #3948544
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep #258
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep #4026531840
|
||||
|
||||
; Test #<const>
|
||||
|
||||
; var 2.1 - 0x00ab00ab
|
||||
define i32 @t2_const_var2_1_ok_1(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 11206827 ; 0x00ab00ab
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_1_fail_1(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 11206843 ; 0x00ab00bb
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_1_fail_2(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 27984043 ; 0x01ab00ab
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_1_fail_3(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 27984299 ; 0x01ab01ab
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_1_fail_4(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 28027649 ; 0x01abab01
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
; var 2.2 - 0xab00ab00
|
||||
define i32 @t2_const_var2_2_ok_1(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 2868947712 ; 0xab00ab00
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_2_fail_1(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 2868951552 ; 0xab00ba00
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_2_fail_2(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 2868947728 ; 0xab00ab10
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_2_fail_3(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 2869996304 ; 0xab10ab10
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_2_fail_4(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 279685904 ; 0x10abab10
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
; var 2.3 - 0xabababab
|
||||
define i32 @t2_const_var2_3_ok_1(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 2880154539 ; 0xabababab
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_3_fail_1(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 2880154554 ; 0xabababba
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_3_fail_2(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 2880158379 ; 0xababbaab
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_3_fail_3(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 2881137579 ; 0xabbaabab
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var2_3_fail_4(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 3131812779 ; 0xbaababab
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
; var 3 - 0x0F000000
|
||||
define i32 @t2_const_var3_1_ok_1(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 251658240 ; 0x0F000000
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var3_2_ok_1(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 3948544 ; 0b00000000001111000100000000000000
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var3_2_fail_1(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 3940352 ; 0b00000000001111000010000000000000
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var3_3_ok_1(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 258 ; 0b00000000000000000000000100000010
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @t2_const_var3_4_ok_1(i32 %lhs) {
|
||||
%ret = add i32 %lhs, 4026531840 ; 0xF0000000
|
||||
ret i32 %ret
|
||||
}
|
||||
|
65
test/CodeGen/ARM/thumb2-mov2.ll
Normal file
65
test/CodeGen/ARM/thumb2-mov2.ll
Normal file
@ -0,0 +1,65 @@
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movt | grep #1234
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movt | grep #1234
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movt | grep #1234
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movt | grep #1234
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | grep movt
|
||||
|
||||
define i32 @t2MOVTi16_ok_1(i32 %a) {
|
||||
%1 = and i32 %a, 65535
|
||||
%2 = shl i32 1234, 16
|
||||
%3 = or i32 %1, %2
|
||||
|
||||
ret i32 %3
|
||||
}
|
||||
|
||||
define i32 @t2MOVTi16_test_1(i32 %a) {
|
||||
%1 = shl i32 255, 8
|
||||
%2 = shl i32 1234, 8
|
||||
%3 = or i32 %1, 255 ; This give us 0xFFFF in %3
|
||||
%4 = shl i32 %2, 8 ; This gives us (1234 << 16) in %4
|
||||
%5 = and i32 %a, %3
|
||||
%6 = or i32 %4, %5
|
||||
|
||||
ret i32 %6
|
||||
}
|
||||
|
||||
define i32 @t2MOVTi16_test_2(i32 %a) {
|
||||
%1 = shl i32 255, 8
|
||||
%2 = shl i32 1234, 8
|
||||
%3 = or i32 %1, 255 ; This give us 0xFFFF in %3
|
||||
%4 = shl i32 %2, 6
|
||||
%5 = and i32 %a, %3
|
||||
%6 = shl i32 %4, 2 ; This gives us (1234 << 16) in %6
|
||||
%7 = or i32 %5, %6
|
||||
|
||||
ret i32 %7
|
||||
}
|
||||
|
||||
define i32 @t2MOVTi16_test_3(i32 %a) {
|
||||
%1 = shl i32 255, 8
|
||||
%2 = shl i32 1234, 8
|
||||
%3 = or i32 %1, 255 ; This give us 0xFFFF in %3
|
||||
%4 = shl i32 %2, 6
|
||||
%5 = and i32 %a, %3
|
||||
%6 = shl i32 %4, 2 ; This gives us (1234 << 16) in %6
|
||||
%7 = lshr i32 %6, 6
|
||||
%8 = shl i32 %7, 6
|
||||
%9 = or i32 %5, %8
|
||||
|
||||
ret i32 %9
|
||||
}
|
||||
|
||||
define i32 @t2MOVTi16_test_nomatch_1(i32 %a) {
|
||||
%1 = shl i32 255, 8
|
||||
%2 = shl i32 1234, 8
|
||||
%3 = or i32 %1, 255 ; This give us 0xFFFF in %3
|
||||
%4 = shl i32 %2, 6
|
||||
%5 = and i32 %a, %3
|
||||
%6 = shl i32 %4, 2 ; This gives us (1234 << 16) in %6
|
||||
%7 = lshr i32 %6, 3
|
||||
%8 = or i32 %5, %7
|
||||
|
||||
ret i32 %8
|
||||
}
|
||||
|
||||
|
40
test/CodeGen/ARM/thumb2-shifter.ll
Normal file
40
test/CodeGen/ARM/thumb2-shifter.ll
Normal file
@ -0,0 +1,40 @@
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep lsl
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep lsr
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep asr
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep ror
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov
|
||||
|
||||
define i32 @t2ADDrs_lsl(i32 %X, i32 %Y) {
|
||||
%A = shl i32 %Y, 16
|
||||
%B = add i32 %X, %A
|
||||
ret i32 %B
|
||||
}
|
||||
|
||||
define i32 @t2ADDrs_lsr(i32 %X, i32 %Y) {
|
||||
%A = lshr i32 %Y, 16
|
||||
%B = add i32 %X, %A
|
||||
ret i32 %B
|
||||
}
|
||||
|
||||
define i32 @t2ADDrs_asr(i32 %X, i32 %Y) {
|
||||
%A = ashr i32 %Y, 16
|
||||
%B = add i32 %X, %A
|
||||
ret i32 %B
|
||||
}
|
||||
|
||||
; i32 ror(n) = (x >> n) | (x << (32 - n))
|
||||
define i32 @t2ADDrs_ror(i32 %X, i32 %Y) {
|
||||
%A = lshr i32 %Y, 16
|
||||
%B = shl i32 %Y, 16
|
||||
%C = or i32 %B, %A
|
||||
%R = add i32 %X, %C
|
||||
ret i32 %R
|
||||
}
|
||||
|
||||
define i32 @t2ADDrs_noRegShift(i32 %X, i32 %Y, i8 %sh) {
|
||||
%shift.upgrd.1 = zext i8 %sh to i32
|
||||
%A = shl i32 %Y, %shift.upgrd.1
|
||||
%B = add i32 %X, %A
|
||||
ret i32 %B
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user