diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index 23e1037baac9..97134ee3d11a 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -263,7 +263,7 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) } else { setOperationAction(ISD::MUL, MVT::i64, Expand); setOperationAction(ISD::MULHU, MVT::i32, Expand); - if (!Subtarget->isThumb1Only() && !Subtarget->hasV6Ops()) + if (!Subtarget->hasV6Ops()) setOperationAction(ISD::MULHS, MVT::i32, Expand); } setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); @@ -985,8 +985,8 @@ SDValue ARMTargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) { // FIXME: handle tail calls differently. unsigned CallOpc; - if (Subtarget->isThumb1Only()) { - if (!Subtarget->hasV5TOps() && (!isDirect || isARMFunc)) + if (Subtarget->isThumb()) { + if ((!isDirect || isARMFunc) && !Subtarget->hasV5TOps()) CallOpc = ARMISD::CALL_NOLINK; else CallOpc = isARMFunc ? ARMISD::CALL : ARMISD::tCALL; diff --git a/llvm/lib/Target/ARM/ARMInstrFormats.td b/llvm/lib/Target/ARM/ARMInstrFormats.td index 3194fbc0a96c..fe32c5f669b2 100644 --- a/llvm/lib/Target/ARM/ARMInstrFormats.td +++ b/llvm/lib/Target/ARM/ARMInstrFormats.td @@ -808,7 +808,7 @@ class ThumbI pattern> : ThumbI; -// BL, BLX(1) are translated by assembler into two instructions +// tBL, tBX instructions class TIx2 pattern> : ThumbI; diff --git a/llvm/lib/Target/ARM/ARMInstrThumb.td b/llvm/lib/Target/ARM/ARMInstrThumb.td index b7aa94143107..9917e016dd0a 100644 --- a/llvm/lib/Target/ARM/ARMInstrThumb.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb.td @@ -170,24 +170,26 @@ let isCall = 1, D0, D1, D2, D3, D4, D5, D6, D7, D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, CPSR] in { - def tBL : T1Ix2<(outs), (ins i32imm:$func, variable_ops), + // Also used for Thumb2 + def tBL : TIx2<(outs), (ins i32imm:$func, variable_ops), "bl ${func:call}", [(ARMtcall tglobaladdr:$func)]>, - Requires<[IsThumb1Only, IsNotDarwin]>; + Requires<[IsThumb, IsNotDarwin]>; - // ARMv5T and above - def tBLXi : T1Ix2<(outs), (ins i32imm:$func, variable_ops), + // ARMv5T and above, also used for Thumb2 + def tBLXi : TIx2<(outs), (ins i32imm:$func, variable_ops), "blx ${func:call}", [(ARMcall tglobaladdr:$func)]>, - Requires<[IsThumb1Only, HasV5T, IsNotDarwin]>; + Requires<[IsThumb, HasV5T, IsNotDarwin]>; - def tBLXr : T1I<(outs), (ins tGPR:$func, variable_ops), + // Also used for Thumb2 + def tBLXr : TI<(outs), (ins GPR:$func, variable_ops), "blx $func", - [(ARMtcall tGPR:$func)]>, - Requires<[IsThumb1Only, HasV5T, IsNotDarwin]>; + [(ARMtcall GPR:$func)]>, + Requires<[IsThumb, HasV5T, IsNotDarwin]>; // ARMv4T - def tBX : T1Ix2<(outs), (ins tGPR:$func, variable_ops), + def tBX : TIx2<(outs), (ins tGPR:$func, variable_ops), "mov lr, pc\n\tbx $func", [(ARMcall_nolink tGPR:$func)]>, Requires<[IsThumb1Only, IsNotDarwin]>; @@ -199,24 +201,26 @@ let isCall = 1, D0, D1, D2, D3, D4, D5, D6, D7, D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, CPSR] in { - def tBLr9 : T1Ix2<(outs), (ins i32imm:$func, variable_ops), + // Also used for Thumb2 + def tBLr9 : TIx2<(outs), (ins i32imm:$func, variable_ops), "bl ${func:call}", [(ARMtcall tglobaladdr:$func)]>, - Requires<[IsThumb1Only, IsDarwin]>; + Requires<[IsThumb, IsDarwin]>; - // ARMv5T and above - def tBLXi_r9 : T1Ix2<(outs), (ins i32imm:$func, variable_ops), + // ARMv5T and above, also used for Thumb2 + def tBLXi_r9 : TIx2<(outs), (ins i32imm:$func, variable_ops), "blx ${func:call}", [(ARMcall tglobaladdr:$func)]>, - Requires<[IsThumb1Only, HasV5T, IsDarwin]>; + Requires<[IsThumb, HasV5T, IsDarwin]>; - def tBLXr_r9 : T1I<(outs), (ins tGPR:$func, variable_ops), + // Also used for Thumb2 + def tBLXr_r9 : TI<(outs), (ins GPR:$func, variable_ops), "blx $func", - [(ARMtcall tGPR:$func)]>, - Requires<[IsThumb1Only, HasV5T, IsDarwin]>; + [(ARMtcall GPR:$func)]>, + Requires<[IsThumb, HasV5T, IsDarwin]>; // ARMv4T - def tBXr9 : T1Ix2<(outs), (ins tGPR:$func, variable_ops), + def tBXr9 : TIx2<(outs), (ins tGPR:$func, variable_ops), "mov lr, pc\n\tbx $func", [(ARMcall_nolink tGPR:$func)]>, Requires<[IsThumb1Only, IsDarwin]>; @@ -229,7 +233,7 @@ let isBranch = 1, isTerminator = 1 in { [(br bb:$target)]>; // Far jump - def tBfar : T1Ix2<(outs), (ins brtarget:$target), + def tBfar : TIx2<(outs), (ins brtarget:$target), "bl $target\t@ far jump",[]>; def tBR_JTr : T1JTI<(outs), @@ -601,7 +605,7 @@ def tLEApcrelJT : T1I<(outs tGPR:$dst), (ins i32imm:$label, i32imm:$id), // __aeabi_read_tp preserves the registers r1-r3. let isCall = 1, Defs = [R0, LR] in { - def tTPsoft : T1Ix2<(outs), (ins), + def tTPsoft : TIx2<(outs), (ins), "bl __aeabi_read_tp", [(set R0, ARMthread_pointer)]>; } @@ -636,20 +640,20 @@ def : T1Pat<(ARMWrapperJT tjumptable:$dst, imm:$id), // Direct calls def : T1Pat<(ARMtcall texternalsym:$func), (tBL texternalsym:$func)>, - Requires<[IsThumb1Only, IsNotDarwin]>; + Requires<[IsThumb, IsNotDarwin]>; def : T1Pat<(ARMtcall texternalsym:$func), (tBLr9 texternalsym:$func)>, - Requires<[IsThumb1Only, IsDarwin]>; + Requires<[IsThumb, IsDarwin]>; def : Tv5Pat<(ARMcall texternalsym:$func), (tBLXi texternalsym:$func)>, - Requires<[IsThumb1Only, HasV5T, IsNotDarwin]>; + Requires<[IsThumb, HasV5T, IsNotDarwin]>; def : Tv5Pat<(ARMcall texternalsym:$func), (tBLXi_r9 texternalsym:$func)>, - Requires<[IsThumb1Only, HasV5T, IsDarwin]>; + Requires<[IsThumb, HasV5T, IsDarwin]>; // Indirect calls to ARM routines -def : Tv5Pat<(ARMcall tGPR:$dst), (tBLXr tGPR:$dst)>, - Requires<[IsThumb1Only, HasV5T, IsNotDarwin]>; -def : Tv5Pat<(ARMcall tGPR:$dst), (tBLXr_r9 tGPR:$dst)>, - Requires<[IsThumb1Only, HasV5T, IsDarwin]>; +def : Tv5Pat<(ARMcall GPR:$dst), (tBLXr GPR:$dst)>, + Requires<[IsThumb, HasV5T, IsNotDarwin]>; +def : Tv5Pat<(ARMcall GPR:$dst), (tBLXr_r9 GPR:$dst)>, + Requires<[IsThumb, HasV5T, IsDarwin]>; // zextload i1 -> zextload i8 def : T1Pat<(zextloadi1 t_addrmode_s1:$addr), diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td index 361afcc4f05a..bb4f11a307be 100644 --- a/llvm/lib/Target/ARM/ARMInstrThumb2.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td @@ -1016,40 +1016,6 @@ let isReturn = 1, isTerminator = 1, mayLoad = 1 in "ldm${addr:submode}${p} $addr, $dst1", []>; -// On non-Darwin platforms R9 is callee-saved. -let isCall = 1, - Defs = [R0, R1, R2, R3, R12, LR, - D0, D1, D2, D3, D4, D5, D6, D7, - D16, D17, D18, D19, D20, D21, D22, D23, - D24, D25, D26, D27, D28, D29, D30, D31, CPSR] in { -def t2BL : T2XI<(outs), (ins i32imm:$func, variable_ops), - "bl ${func:call}", - [(ARMcall tglobaladdr:$func)]>, - Requires<[IsThumb2, IsNotDarwin]>; - -def t2BLX : T2XI<(outs), (ins GPR:$func, variable_ops), - "blx $func", - [(ARMcall GPR:$func)]>, - Requires<[IsThumb2, IsNotDarwin]>; -} - -// On Darwin R9 is call-clobbered. -let isCall = 1, - Defs = [R0, R1, R2, R3, R9, R12, LR, - D0, D1, D2, D3, D4, D5, D6, D7, - D16, D17, D18, D19, D20, D21, D22, D23, - D24, D25, D26, D27, D28, D29, D30, D31, CPSR] in { -def t2BLr9 : T2XI<(outs), (ins i32imm:$func, variable_ops), - "bl ${func:call}", - [(ARMcall tglobaladdr:$func)]>, - Requires<[IsThumb2, IsDarwin]>; - -def t2BLXr9 : T2XI<(outs), (ins GPR:$func, variable_ops), - "blx $func", - [(ARMcall GPR:$func)]>, - Requires<[IsThumb2, IsDarwin]>; -} - let isBranch = 1, isTerminator = 1, isBarrier = 1 in { let isPredicable = 1 in def t2B : T2XI<(outs), (ins brtarget:$target), @@ -1103,9 +1069,3 @@ def : T2Pat<(ARMWrapperJT tjumptable:$dst, imm:$id), def : T2Pat<(i32 imm:$src), (t2MOVTi16 (t2MOVi16 (t2_lo16 imm:$src)), (t2_hi16 imm:$src))>; - -// Direct calls -def : T2Pat<(ARMcall texternalsym:$func), (t2BL texternalsym:$func)>, - Requires<[IsThumb2, IsNotDarwin]>; -def : T2Pat<(ARMcall texternalsym:$func), (t2BLr9 texternalsym:$func)>, - Requires<[IsThumb2, IsDarwin]>; diff --git a/llvm/lib/Target/ARM/ARMSubtarget.cpp b/llvm/lib/Target/ARM/ARMSubtarget.cpp index e61108857413..d30592b0f4ca 100644 --- a/llvm/lib/Target/ARM/ARMSubtarget.cpp +++ b/llvm/lib/Target/ARM/ARMSubtarget.cpp @@ -75,6 +75,10 @@ ARMSubtarget::ARMSubtarget(const Module &M, const std::string &FS, } } + // Thumb2 implies at least V6T2. + if (ARMArchVersion < V6T2 && ThumbMode >= Thumb2) + ARMArchVersion = V6T2; + if (Len >= 10) { if (TT.find("-darwin") != std::string::npos) // arm-darwin diff --git a/llvm/test/CodeGen/Thumb2/thumb2-call.ll b/llvm/test/CodeGen/Thumb2/thumb2-call.ll new file mode 100644 index 000000000000..23a9b16be06c --- /dev/null +++ b/llvm/test/CodeGen/Thumb2/thumb2-call.ll @@ -0,0 +1,20 @@ +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | FileCheck %s + +@t = weak global i32 ()* null ; [#uses=1] + +declare void @g(i32, i32, i32, i32) + +define void @f() { +; CHECK: f: +; CHECK: blx + call void @g( i32 1, i32 2, i32 3, i32 4 ) + ret void +} + +define void @h() { +; CHECK: h: +; CHECK: blx r0 + %tmp = load i32 ()** @t ; [#uses=1] + %tmp.upgrd.2 = tail call i32 %tmp( ) ; [#uses=0] + ret void +} diff --git a/llvm/test/CodeGen/Thumb2/thumb2-mulhi.ll b/llvm/test/CodeGen/Thumb2/thumb2-mulhi.ll index f2c5233f2870..7b41509f79c7 100644 --- a/llvm/test/CodeGen/Thumb2/thumb2-mulhi.ll +++ b/llvm/test/CodeGen/Thumb2/thumb2-mulhi.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep smull | count 1 +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep smmul | count 1 ; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep umull | count 1 define i32 @smulhi(i32 %x, i32 %y) {