Add support for the moveq instruction, which is both faster and smaller (1/2 to 1/3 the size) than a move with immediate to register. This change introduces the instruction, along with a set of pseudoinstructions to handle immediate moves to a register that is lowered post-RA. Pseudos are used as moveq can only write to the full register, which makes matching i8 and i16 immediate loads difficult in tablegen. Furthermore, selecting moveq before RA constrains that immediate to be moved into a data register, which may not be optimal. The bulk of this change are fixes to existing tests, which cover the new functionality sufficiently.
353 lines
9.1 KiB
LLVM
353 lines
9.1 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
; RUN: llc < %s -mtriple=m68k-linux -verify-machineinstrs | FileCheck %s
|
|
|
|
; op reg, reg
|
|
|
|
define zeroext i8 @andb(i8 zeroext %a, i8 zeroext %b) nounwind {
|
|
; CHECK-LABEL: andb:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.b (11,%sp), %d0
|
|
; CHECK-NEXT: move.b (7,%sp), %d1
|
|
; CHECK-NEXT: and.b %d0, %d1
|
|
; CHECK-NEXT: move.l %d1, %d0
|
|
; CHECK-NEXT: and.l #255, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = and i8 %a, %b
|
|
ret i8 %1
|
|
}
|
|
|
|
define zeroext i16 @andw(i16 zeroext %a, i16 zeroext %b) nounwind {
|
|
; CHECK-LABEL: andw:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.w (10,%sp), %d0
|
|
; CHECK-NEXT: move.w (6,%sp), %d1
|
|
; CHECK-NEXT: and.w %d0, %d1
|
|
; CHECK-NEXT: move.l %d1, %d0
|
|
; CHECK-NEXT: and.l #65535, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = and i16 %a, %b
|
|
ret i16 %1
|
|
}
|
|
|
|
define i32 @andl(i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: andl:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (8,%sp), %d1
|
|
; CHECK-NEXT: move.l (4,%sp), %d0
|
|
; CHECK-NEXT: and.l %d1, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = and i32 %a, %b
|
|
ret i32 %1
|
|
}
|
|
|
|
define zeroext i8 @orb(i8 zeroext %a, i8 zeroext %b) nounwind {
|
|
; CHECK-LABEL: orb:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.b (11,%sp), %d0
|
|
; CHECK-NEXT: move.b (7,%sp), %d1
|
|
; CHECK-NEXT: or.b %d0, %d1
|
|
; CHECK-NEXT: move.l %d1, %d0
|
|
; CHECK-NEXT: and.l #255, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = or i8 %a, %b
|
|
ret i8 %1
|
|
}
|
|
|
|
define zeroext i16 @orw(i16 zeroext %a, i16 zeroext %b) nounwind {
|
|
; CHECK-LABEL: orw:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.w (10,%sp), %d0
|
|
; CHECK-NEXT: move.w (6,%sp), %d1
|
|
; CHECK-NEXT: or.w %d0, %d1
|
|
; CHECK-NEXT: move.l %d1, %d0
|
|
; CHECK-NEXT: and.l #65535, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = or i16 %a, %b
|
|
ret i16 %1
|
|
}
|
|
|
|
define i32 @orl(i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: orl:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (8,%sp), %d1
|
|
; CHECK-NEXT: move.l (4,%sp), %d0
|
|
; CHECK-NEXT: or.l %d1, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = or i32 %a, %b
|
|
ret i32 %1
|
|
}
|
|
|
|
define zeroext i8 @eorb(i8 zeroext %a, i8 zeroext %b) nounwind {
|
|
; CHECK-LABEL: eorb:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.b (11,%sp), %d0
|
|
; CHECK-NEXT: move.b (7,%sp), %d1
|
|
; CHECK-NEXT: eor.b %d0, %d1
|
|
; CHECK-NEXT: move.l %d1, %d0
|
|
; CHECK-NEXT: and.l #255, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = xor i8 %a, %b
|
|
ret i8 %1
|
|
}
|
|
|
|
define zeroext i16 @eorw(i16 zeroext %a, i16 zeroext %b) nounwind {
|
|
; CHECK-LABEL: eorw:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.w (10,%sp), %d0
|
|
; CHECK-NEXT: move.w (6,%sp), %d1
|
|
; CHECK-NEXT: eor.w %d0, %d1
|
|
; CHECK-NEXT: move.l %d1, %d0
|
|
; CHECK-NEXT: and.l #65535, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = xor i16 %a, %b
|
|
ret i16 %1
|
|
}
|
|
|
|
define i32 @eorl(i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: eorl:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (8,%sp), %d1
|
|
; CHECK-NEXT: move.l (4,%sp), %d0
|
|
; CHECK-NEXT: eor.l %d1, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = xor i32 %a, %b
|
|
ret i32 %1
|
|
}
|
|
|
|
; op reg, imm
|
|
; For type i8 and i16, value is loaded from memory to avoid optimizing it to *.l
|
|
|
|
define void @andib(ptr %a) nounwind {
|
|
; CHECK-LABEL: andib:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (4,%sp), %a0
|
|
; CHECK-NEXT: move.b (%a0), %d0
|
|
; CHECK-NEXT: and.b #18, %d0
|
|
; CHECK-NEXT: move.b %d0, (%a0)
|
|
; CHECK-NEXT: rts
|
|
%1 = load i8, ptr %a
|
|
%2 = and i8 %1, 18
|
|
store i8 %2, ptr %a
|
|
ret void
|
|
}
|
|
|
|
define void @andiw(ptr %a) nounwind {
|
|
; CHECK-LABEL: andiw:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (4,%sp), %a0
|
|
; CHECK-NEXT: move.w (%a0), %d0
|
|
; CHECK-NEXT: and.w #4660, %d0
|
|
; CHECK-NEXT: move.w %d0, (%a0)
|
|
; CHECK-NEXT: rts
|
|
%1 = load i16, ptr %a
|
|
%2 = and i16 %1, 4660
|
|
store i16 %2, ptr %a
|
|
ret void
|
|
}
|
|
|
|
define i32 @andil(i32 %a) nounwind {
|
|
; CHECK-LABEL: andil:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (4,%sp), %d0
|
|
; CHECK-NEXT: and.l #305419896, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = and i32 %a, 305419896
|
|
ret i32 %1
|
|
}
|
|
|
|
define void @orib(ptr %a) nounwind {
|
|
; CHECK-LABEL: orib:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (4,%sp), %a0
|
|
; CHECK-NEXT: move.b (%a0), %d0
|
|
; CHECK-NEXT: or.b #18, %d0
|
|
; CHECK-NEXT: move.b %d0, (%a0)
|
|
; CHECK-NEXT: rts
|
|
%1 = load i8, ptr %a
|
|
%2 = or i8 %1, 18
|
|
store i8 %2, ptr %a
|
|
ret void
|
|
}
|
|
|
|
define void @oriw(ptr %a) nounwind {
|
|
; CHECK-LABEL: oriw:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (4,%sp), %a0
|
|
; CHECK-NEXT: move.w (%a0), %d0
|
|
; CHECK-NEXT: or.w #4660, %d0
|
|
; CHECK-NEXT: move.w %d0, (%a0)
|
|
; CHECK-NEXT: rts
|
|
%1 = load i16, ptr %a
|
|
%2 = or i16 %1, 4660
|
|
store i16 %2, ptr %a
|
|
ret void
|
|
}
|
|
|
|
define i32 @oril(i32 %a) nounwind {
|
|
; CHECK-LABEL: oril:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (4,%sp), %d0
|
|
; CHECK-NEXT: or.l #305419896, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = or i32 %a, 305419896
|
|
ret i32 %1
|
|
}
|
|
|
|
define void @eorib(ptr %a) nounwind {
|
|
; CHECK-LABEL: eorib:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (4,%sp), %a0
|
|
; CHECK-NEXT: move.b (%a0), %d0
|
|
; CHECK-NEXT: eori.b #18, %d0
|
|
; CHECK-NEXT: move.b %d0, (%a0)
|
|
; CHECK-NEXT: rts
|
|
%1 = load i8, ptr %a
|
|
%2 = xor i8 %1, 18
|
|
store i8 %2, ptr %a
|
|
ret void
|
|
}
|
|
|
|
define void @eoriw(ptr %a) nounwind {
|
|
; CHECK-LABEL: eoriw:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (4,%sp), %a0
|
|
; CHECK-NEXT: move.w (%a0), %d0
|
|
; CHECK-NEXT: eori.w #4660, %d0
|
|
; CHECK-NEXT: move.w %d0, (%a0)
|
|
; CHECK-NEXT: rts
|
|
%1 = load i16, ptr %a
|
|
%2 = xor i16 %1, 4660
|
|
store i16 %2, ptr %a
|
|
ret void
|
|
}
|
|
|
|
define i32 @eoril(i32 %a) nounwind {
|
|
; CHECK-LABEL: eoril:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: move.l (4,%sp), %d0
|
|
; CHECK-NEXT: eori.l #305419896, %d0
|
|
; CHECK-NEXT: rts
|
|
%1 = xor i32 %a, 305419896
|
|
ret i32 %1
|
|
}
|
|
|
|
define i64 @lshr64(i64 %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: lshr64:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: suba.l #12, %sp
|
|
; CHECK-NEXT: movem.l %d2-%d4, (0,%sp) ; 16-byte Folded Spill
|
|
; CHECK-NEXT: move.l (28,%sp), %d3
|
|
; CHECK-NEXT: move.l (16,%sp), %d2
|
|
; CHECK-NEXT: move.l %d3, %d1
|
|
; CHECK-NEXT: add.l #-32, %d1
|
|
; CHECK-NEXT: bmi .LBB18_1
|
|
; CHECK-NEXT: ; %bb.2:
|
|
; CHECK-NEXT: moveq #0, %d0
|
|
; CHECK-NEXT: bra .LBB18_3
|
|
; CHECK-NEXT: .LBB18_1:
|
|
; CHECK-NEXT: move.l %d2, %d0
|
|
; CHECK-NEXT: lsr.l %d3, %d0
|
|
; CHECK-NEXT: .LBB18_3:
|
|
; CHECK-NEXT: move.l %d3, %d4
|
|
; CHECK-NEXT: add.l #-32, %d4
|
|
; CHECK-NEXT: bmi .LBB18_4
|
|
; CHECK-NEXT: ; %bb.5:
|
|
; CHECK-NEXT: lsr.l %d1, %d2
|
|
; CHECK-NEXT: move.l %d2, %d1
|
|
; CHECK-NEXT: bra .LBB18_6
|
|
; CHECK-NEXT: .LBB18_4:
|
|
; CHECK-NEXT: move.l %d3, %d4
|
|
; CHECK-NEXT: eori.l #31, %d4
|
|
; CHECK-NEXT: lsl.l #1, %d2
|
|
; CHECK-NEXT: move.l (20,%sp), %d1
|
|
; CHECK-NEXT: lsl.l %d4, %d2
|
|
; CHECK-NEXT: lsr.l %d3, %d1
|
|
; CHECK-NEXT: or.l %d2, %d1
|
|
; CHECK-NEXT: .LBB18_6:
|
|
; CHECK-NEXT: movem.l (0,%sp), %d2-%d4 ; 16-byte Folded Reload
|
|
; CHECK-NEXT: adda.l #12, %sp
|
|
; CHECK-NEXT: rts
|
|
%1 = lshr i64 %a, %b
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @ashr64(i64 %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: ashr64:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: suba.l #8, %sp
|
|
; CHECK-NEXT: movem.l %d2-%d3, (0,%sp) ; 12-byte Folded Spill
|
|
; CHECK-NEXT: move.l (24,%sp), %d2
|
|
; CHECK-NEXT: move.l (12,%sp), %d0
|
|
; CHECK-NEXT: move.l %d2, %d3
|
|
; CHECK-NEXT: add.l #-32, %d3
|
|
; CHECK-NEXT: move.l %d2, %d1
|
|
; CHECK-NEXT: add.l #-32, %d1
|
|
; CHECK-NEXT: bmi .LBB19_1
|
|
; CHECK-NEXT: ; %bb.2:
|
|
; CHECK-NEXT: move.l %d0, %d1
|
|
; CHECK-NEXT: asr.l %d3, %d1
|
|
; CHECK-NEXT: bra .LBB19_3
|
|
; CHECK-NEXT: .LBB19_1:
|
|
; CHECK-NEXT: move.l %d2, %d1
|
|
; CHECK-NEXT: eori.l #31, %d1
|
|
; CHECK-NEXT: move.l %d0, %d3
|
|
; CHECK-NEXT: lsl.l #1, %d3
|
|
; CHECK-NEXT: lsl.l %d1, %d3
|
|
; CHECK-NEXT: move.l (16,%sp), %d1
|
|
; CHECK-NEXT: lsr.l %d2, %d1
|
|
; CHECK-NEXT: or.l %d3, %d1
|
|
; CHECK-NEXT: .LBB19_3:
|
|
; CHECK-NEXT: move.l %d2, %d3
|
|
; CHECK-NEXT: add.l #-32, %d3
|
|
; CHECK-NEXT: bmi .LBB19_5
|
|
; CHECK-NEXT: ; %bb.4:
|
|
; CHECK-NEXT: moveq #31, %d2
|
|
; CHECK-NEXT: .LBB19_5:
|
|
; CHECK-NEXT: asr.l %d2, %d0
|
|
; CHECK-NEXT: movem.l (0,%sp), %d2-%d3 ; 12-byte Folded Reload
|
|
; CHECK-NEXT: adda.l #8, %sp
|
|
; CHECK-NEXT: rts
|
|
%1 = ashr i64 %a, %b
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @shl64(i64 %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: shl64:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: suba.l #12, %sp
|
|
; CHECK-NEXT: movem.l %d2-%d4, (0,%sp) ; 16-byte Folded Spill
|
|
; CHECK-NEXT: move.l (28,%sp), %d3
|
|
; CHECK-NEXT: move.l (20,%sp), %d2
|
|
; CHECK-NEXT: move.l %d3, %d0
|
|
; CHECK-NEXT: add.l #-32, %d0
|
|
; CHECK-NEXT: bmi .LBB20_1
|
|
; CHECK-NEXT: ; %bb.2:
|
|
; CHECK-NEXT: moveq #0, %d1
|
|
; CHECK-NEXT: bra .LBB20_3
|
|
; CHECK-NEXT: .LBB20_1:
|
|
; CHECK-NEXT: move.l %d2, %d1
|
|
; CHECK-NEXT: lsl.l %d3, %d1
|
|
; CHECK-NEXT: .LBB20_3:
|
|
; CHECK-NEXT: move.l %d3, %d4
|
|
; CHECK-NEXT: add.l #-32, %d4
|
|
; CHECK-NEXT: bmi .LBB20_4
|
|
; CHECK-NEXT: ; %bb.5:
|
|
; CHECK-NEXT: lsl.l %d0, %d2
|
|
; CHECK-NEXT: move.l %d2, %d0
|
|
; CHECK-NEXT: bra .LBB20_6
|
|
; CHECK-NEXT: .LBB20_4:
|
|
; CHECK-NEXT: move.l %d3, %d4
|
|
; CHECK-NEXT: eori.l #31, %d4
|
|
; CHECK-NEXT: lsr.l #1, %d2
|
|
; CHECK-NEXT: move.l (16,%sp), %d0
|
|
; CHECK-NEXT: lsr.l %d4, %d2
|
|
; CHECK-NEXT: lsl.l %d3, %d0
|
|
; CHECK-NEXT: or.l %d2, %d0
|
|
; CHECK-NEXT: .LBB20_6:
|
|
; CHECK-NEXT: movem.l (0,%sp), %d2-%d4 ; 16-byte Folded Reload
|
|
; CHECK-NEXT: adda.l #12, %sp
|
|
; CHECK-NEXT: rts
|
|
%1 = shl i64 %a, %b
|
|
ret i64 %1
|
|
}
|