1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[ARM] Make fullfp16 instructions not conditionalisable.

More or less all the instructions defined in the v8.2a full-fp16
extension are defined as UNPREDICTABLE if you put them in an IT block
(Thumb) or use with any condition other than AL (ARM). LLVM didn't
know that, and was happy to conditionalise them.

In order to force these instructions to count as not predicable, I had
to make a small Tablegen change. The code generation back end mostly
decides if an instruction was predicable by looking for something it
can identify as a predicate operand; there's an isPredicable bit flag
that overrides that check in the positive direction, but nothing that
overrides it in the negative direction.

(I considered the alternative approach of actually removing the
predicate operand from those instructions, but thought that it would
be more painful overall for instructions differing only in data type
to have different shapes of operand list. This way, the only code that
has to notice the difference is the if-converter.)

So I've added an isUnpredicable bit alongside isPredicable, and set
that bit on the right subset of FP16 instructions, and also on the
VSEL, VMAXNM/VMINNM and VRINT[ANPM] families which should be
unpredicable for all data types.

I've included a couple of representative regression tests, both of
which previously caused an fp16 instruction to be conditionalised in
ARM state and (with -arm-no-restrict-it) to be put in an IT block in
Thumb.

Reviewers: SjoerdMeijer, t.p.northover, efriedma

Reviewed By: efriedma

Subscribers: jdoerfert, javed.absar, kristof.beyls, hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D57823

llvm-svn: 354768
This commit is contained in:
Simon Tatham 2019-02-25 10:39:53 +00:00
parent 8691a62a19
commit fb51a50eef
10 changed files with 297 additions and 10 deletions

View File

@ -456,7 +456,11 @@ class Instruction {
bit isCommutable = 0; // Is this 3 operand instruction commutable? bit isCommutable = 0; // Is this 3 operand instruction commutable?
bit isTerminator = 0; // Is this part of the terminator for a basic block? bit isTerminator = 0; // Is this part of the terminator for a basic block?
bit isReMaterializable = 0; // Is this instruction re-materializable? bit isReMaterializable = 0; // Is this instruction re-materializable?
bit isPredicable = 0; // Is this instruction predicable? bit isPredicable = 0; // 1 means this instruction is predicable
// even if it does not have any operand
// tablegen can identify as a predicate
bit isUnpredicable = 0; // 1 means this instruction is not predicable
// even if it _does_ have a predicate operand
bit hasDelaySlot = 0; // Does this instruction have an delay slot? bit hasDelaySlot = 0; // Does this instruction have an delay slot?
bit usesCustomInserter = 0; // Pseudo instr needing special help. bit usesCustomInserter = 0; // Pseudo instr needing special help.
bit hasPostISelHook = 0; // To be *adjusted* after isel by target hook. bit hasPostISelHook = 0; // To be *adjusted* after isel by target hook.

View File

@ -1555,6 +1555,8 @@ class AHI5<bits<4> opcod1, bits<2> opcod2, dag oops, dag iops,
// Loads & stores operate on both NEON and VFP pipelines. // Loads & stores operate on both NEON and VFP pipelines.
let D = VFPNeonDomain; let D = VFPNeonDomain;
let isUnpredicable = 1; // FP16 instructions cannot in general be conditional
} }
// VFP Load / store multiple pseudo instructions. // VFP Load / store multiple pseudo instructions.
@ -1902,6 +1904,8 @@ class AHuI<bits<5> opcod1, bits<2> opcod2, bits<4> opcod3, bits<2> opcod4,
let Inst{11-8} = 0b1001; // Half precision let Inst{11-8} = 0b1001; // Half precision
let Inst{7-6} = opcod4; let Inst{7-6} = opcod4;
let Inst{4} = opcod5; let Inst{4} = opcod5;
let isUnpredicable = 1; // FP16 instructions cannot in general be conditional
} }
// Half precision, unary, non-predicated // Half precision, unary, non-predicated
@ -1930,6 +1934,8 @@ class AHuInp<bits<5> opcod1, bits<2> opcod2, bits<4> opcod3, bits<2> opcod4,
let Inst{11-8} = 0b1001; // Half precision let Inst{11-8} = 0b1001; // Half precision
let Inst{7-6} = opcod4; let Inst{7-6} = opcod4;
let Inst{4} = opcod5; let Inst{4} = opcod5;
let isUnpredicable = 1; // FP16 instructions cannot in general be conditional
} }
// Half precision, binary // Half precision, binary
@ -1956,6 +1962,8 @@ class AHbI<bits<5> opcod1, bits<2> opcod2, bit op6, bit op4, dag oops, dag iops,
let Inst{11-8} = 0b1001; // Half precision let Inst{11-8} = 0b1001; // Half precision
let Inst{6} = op6; let Inst{6} = op6;
let Inst{4} = op4; let Inst{4} = op4;
let isUnpredicable = 1; // FP16 instructions cannot in general be conditional
} }
// Half precision, binary, not predicated // Half precision, binary, not predicated
@ -1985,6 +1993,8 @@ class AHbInp<bits<5> opcod1, bits<2> opcod2, bit opcod3, dag oops, dag iops,
let Inst{11-8} = 0b1001; // Half precision let Inst{11-8} = 0b1001; // Half precision
let Inst{6} = opcod3; let Inst{6} = opcod3;
let Inst{4} = 0; let Inst{4} = 0;
let isUnpredicable = 1; // FP16 instructions cannot in general be conditional
} }
// VFP conversion instructions // VFP conversion instructions

View File

@ -129,6 +129,7 @@ def VLDRS : ASI5<0b1101, 0b01, (outs SPR:$Sd), (ins addrmode5:$addr),
let D = VFPNeonDomain; let D = VFPNeonDomain;
} }
let isUnpredicable = 1 in
def VLDRH : AHI5<0b1101, 0b01, (outs HPR:$Sd), (ins addrmode5fp16:$addr), def VLDRH : AHI5<0b1101, 0b01, (outs HPR:$Sd), (ins addrmode5fp16:$addr),
IIC_fpLoad16, "vldr", ".16\t$Sd, $addr", IIC_fpLoad16, "vldr", ".16\t$Sd, $addr",
[(set HPR:$Sd, (alignedload16 addrmode5fp16:$addr))]>, [(set HPR:$Sd, (alignedload16 addrmode5fp16:$addr))]>,
@ -148,6 +149,7 @@ def VSTRS : ASI5<0b1101, 0b00, (outs), (ins SPR:$Sd, addrmode5:$addr),
let D = VFPNeonDomain; let D = VFPNeonDomain;
} }
let isUnpredicable = 1 in
def VSTRH : AHI5<0b1101, 0b00, (outs), (ins HPR:$Sd, addrmode5fp16:$addr), def VSTRH : AHI5<0b1101, 0b00, (outs), (ins HPR:$Sd, addrmode5fp16:$addr),
IIC_fpStore16, "vstr", ".16\t$Sd, $addr", IIC_fpStore16, "vstr", ".16\t$Sd, $addr",
[(alignedstore16 HPR:$Sd, addrmode5fp16:$addr)]>, [(alignedstore16 HPR:$Sd, addrmode5fp16:$addr)]>,
@ -451,7 +453,7 @@ def VNMULH : AHbI<0b11100, 0b10, 1, 0,
multiclass vsel_inst<string op, bits<2> opc, int CC> { multiclass vsel_inst<string op, bits<2> opc, int CC> {
let DecoderNamespace = "VFPV8", PostEncoderMethod = "", let DecoderNamespace = "VFPV8", PostEncoderMethod = "",
Uses = [CPSR], AddedComplexity = 4 in { Uses = [CPSR], AddedComplexity = 4, isUnpredicable = 1 in {
def H : AHbInp<0b11100, opc, 0, def H : AHbInp<0b11100, opc, 0,
(outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm), (outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm),
NoItinerary, !strconcat("vsel", op, ".f16\t$Sd, $Sn, $Sm"), NoItinerary, !strconcat("vsel", op, ".f16\t$Sd, $Sn, $Sm"),
@ -479,7 +481,8 @@ defm VSELEQ : vsel_inst<"eq", 0b00, 0>;
defm VSELVS : vsel_inst<"vs", 0b01, 6>; defm VSELVS : vsel_inst<"vs", 0b01, 6>;
multiclass vmaxmin_inst<string op, bit opc, SDNode SD> { multiclass vmaxmin_inst<string op, bit opc, SDNode SD> {
let DecoderNamespace = "VFPV8", PostEncoderMethod = "" in { let DecoderNamespace = "VFPV8", PostEncoderMethod = "",
isUnpredicable = 1 in {
def H : AHbInp<0b11101, 0b00, opc, def H : AHbInp<0b11101, 0b00, opc,
(outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm), (outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm),
NoItinerary, !strconcat(op, ".f16\t$Sd, $Sn, $Sm"), NoItinerary, !strconcat(op, ".f16\t$Sd, $Sn, $Sm"),
@ -947,7 +950,8 @@ defm VRINTX : vrint_inst_zrx<"x", 1, 0, frint>;
multiclass vrint_inst_anpm<string opc, bits<2> rm, multiclass vrint_inst_anpm<string opc, bits<2> rm,
SDPatternOperator node = null_frag> { SDPatternOperator node = null_frag> {
let PostEncoderMethod = "", DecoderNamespace = "VFPV8" in { let PostEncoderMethod = "", DecoderNamespace = "VFPV8",
isUnpredicable = 1 in {
def H : AHuInp<0b11101, 0b11, 0b1000, 0b01, 0, def H : AHuInp<0b11101, 0b11, 0b1000, 0b01, 0,
(outs SPR:$Sd), (ins SPR:$Sm), (outs SPR:$Sd), (ins SPR:$Sm),
NoItinerary, !strconcat("vrint", opc, ".f16\t$Sd, $Sm"), NoItinerary, !strconcat("vrint", opc, ".f16\t$Sd, $Sm"),
@ -1012,7 +1016,7 @@ def VMOVS : ASuI<0b11101, 0b11, 0b0000, 0b01, 0,
IIC_fpUNA32, "vmov", ".f32\t$Sd, $Sm", []>; IIC_fpUNA32, "vmov", ".f32\t$Sd, $Sm", []>;
} // isMoveReg } // isMoveReg
let PostEncoderMethod = "", DecoderNamespace = "VFPV8" in { let PostEncoderMethod = "", DecoderNamespace = "VFPV8", isUnpredicable = 1 in {
def VMOVH : ASuInp<0b11101, 0b11, 0b0000, 0b01, 0, def VMOVH : ASuInp<0b11101, 0b11, 0b0000, 0b01, 0,
(outs SPR:$Sd), (ins SPR:$Sm), (outs SPR:$Sd), (ins SPR:$Sm),
IIC_fpUNA16, "vmovx.f16\t$Sd, $Sm", []>, IIC_fpUNA16, "vmovx.f16\t$Sd, $Sm", []>,
@ -1221,6 +1225,8 @@ def VMOVRH : AVConv2I<0b11100001, 0b1001,
let Inst{6-5} = 0b00; let Inst{6-5} = 0b00;
let Inst{3-0} = 0b0000; let Inst{3-0} = 0b0000;
let isUnpredicable = 1;
} }
// Move R->H, clearing top 16 bits // Move R->H, clearing top 16 bits
@ -1241,6 +1247,8 @@ def VMOVHR : AVConv4I<0b11100000, 0b1001,
let Inst{6-5} = 0b00; let Inst{6-5} = 0b00;
let Inst{3-0} = 0b0000; let Inst{3-0} = 0b0000;
let isUnpredicable = 1;
} }
// FMRDH: SPR -> GPR // FMRDH: SPR -> GPR
@ -1347,6 +1355,7 @@ def VSITOH : AVConv1IHs_Encode<0b11101, 0b11, 0b1000, 0b1001,
[]>, []>,
Sched<[WriteFPCVT]> { Sched<[WriteFPCVT]> {
let Inst{7} = 1; // s32 let Inst{7} = 1; // s32
let isUnpredicable = 1;
} }
def : VFPNoNEONPat<(f16 (sint_to_fp GPR:$a)), def : VFPNoNEONPat<(f16 (sint_to_fp GPR:$a)),
@ -1392,6 +1401,7 @@ def VUITOH : AVConv1IHs_Encode<0b11101, 0b11, 0b1000, 0b1001,
[]>, []>,
Sched<[WriteFPCVT]> { Sched<[WriteFPCVT]> {
let Inst{7} = 0; // u32 let Inst{7} = 0; // u32
let isUnpredicable = 1;
} }
def : VFPNoNEONPat<(f16 (uint_to_fp GPR:$a)), def : VFPNoNEONPat<(f16 (uint_to_fp GPR:$a)),
@ -1496,6 +1506,7 @@ def VTOSIZH : AVConv1IsH_Encode<0b11101, 0b11, 0b1101, 0b1001,
[]>, []>,
Sched<[WriteFPCVT]> { Sched<[WriteFPCVT]> {
let Inst{7} = 1; // Z bit let Inst{7} = 1; // Z bit
let isUnpredicable = 1;
} }
def : VFPNoNEONPat<(i32 (fp_to_sint HPR:$a)), def : VFPNoNEONPat<(i32 (fp_to_sint HPR:$a)),
@ -1542,6 +1553,7 @@ def VTOUIZH : AVConv1IsH_Encode<0b11101, 0b11, 0b1100, 0b1001,
[]>, []>,
Sched<[WriteFPCVT]> { Sched<[WriteFPCVT]> {
let Inst{7} = 1; // Z bit let Inst{7} = 1; // Z bit
let isUnpredicable = 1;
} }
def : VFPNoNEONPat<(i32 (fp_to_uint HPR:$a)), def : VFPNoNEONPat<(i32 (fp_to_uint HPR:$a)),
@ -1571,6 +1583,7 @@ def VTOSIRH : AVConv1IsH_Encode<0b11101, 0b11, 0b1101, 0b1001,
[]>, []>,
Sched<[WriteFPCVT]> { Sched<[WriteFPCVT]> {
let Inst{7} = 0; // Z bit let Inst{7} = 0; // Z bit
let isUnpredicable = 1;
} }
def VTOUIRD : AVConv1IsD_Encode<0b11101, 0b11, 0b1100, 0b1011, def VTOUIRD : AVConv1IsD_Encode<0b11101, 0b11, 0b1100, 0b1011,
@ -1595,6 +1608,7 @@ def VTOUIRH : AVConv1IsH_Encode<0b11101, 0b11, 0b1100, 0b1001,
[]>, []>,
Sched<[WriteFPCVT]> { Sched<[WriteFPCVT]> {
let Inst{7} = 0; // Z bit let Inst{7} = 0; // Z bit
let isUnpredicable = 1;
} }
} }
@ -1642,6 +1656,8 @@ class AVConv1XInsD_Encode<bits<5> op1, bits<2> op2, bits<4> op3, bits<4> op4,
let Predicates = [HasVFP2, HasDPVFP]; let Predicates = [HasVFP2, HasDPVFP];
} }
let isUnpredicable = 1 in {
def VTOSHH : AVConv1XInsS_Encode<0b11101, 0b11, 0b1110, 0b1001, 0, def VTOSHH : AVConv1XInsS_Encode<0b11101, 0b11, 0b1110, 0b1001, 0,
(outs SPR:$dst), (ins SPR:$a, fbits16:$fbits), (outs SPR:$dst), (ins SPR:$a, fbits16:$fbits),
IIC_fpCVTHI, "vcvt", ".s16.f16\t$dst, $a, $fbits", []>, IIC_fpCVTHI, "vcvt", ".s16.f16\t$dst, $a, $fbits", []>,
@ -1666,6 +1682,8 @@ def VTOULH : AVConv1XInsS_Encode<0b11101, 0b11, 0b1111, 0b1001, 1,
Requires<[HasFullFP16]>, Requires<[HasFullFP16]>,
Sched<[WriteFPCVT]>; Sched<[WriteFPCVT]>;
} // End of 'let isUnpredicable = 1 in'
def VTOSHS : AVConv1XInsS_Encode<0b11101, 0b11, 0b1110, 0b1010, 0, def VTOSHS : AVConv1XInsS_Encode<0b11101, 0b11, 0b1110, 0b1010, 0,
(outs SPR:$dst), (ins SPR:$a, fbits16:$fbits), (outs SPR:$dst), (ins SPR:$a, fbits16:$fbits),
IIC_fpCVTSI, "vcvt", ".s16.f32\t$dst, $a, $fbits", []>, IIC_fpCVTSI, "vcvt", ".s16.f32\t$dst, $a, $fbits", []>,
@ -1721,6 +1739,8 @@ def VTOULD : AVConv1XInsD_Encode<0b11101, 0b11, 0b1111, 0b1011, 1,
// Fixed-Point to FP: // Fixed-Point to FP:
let isUnpredicable = 1 in {
def VSHTOH : AVConv1XInsS_Encode<0b11101, 0b11, 0b1010, 0b1001, 0, def VSHTOH : AVConv1XInsS_Encode<0b11101, 0b11, 0b1010, 0b1001, 0,
(outs SPR:$dst), (ins SPR:$a, fbits16:$fbits), (outs SPR:$dst), (ins SPR:$a, fbits16:$fbits),
IIC_fpCVTIH, "vcvt", ".f16.s16\t$dst, $a, $fbits", []>, IIC_fpCVTIH, "vcvt", ".f16.s16\t$dst, $a, $fbits", []>,
@ -1745,6 +1765,8 @@ def VULTOH : AVConv1XInsS_Encode<0b11101, 0b11, 0b1011, 0b1001, 1,
Requires<[HasFullFP16]>, Requires<[HasFullFP16]>,
Sched<[WriteFPCVT]>; Sched<[WriteFPCVT]>;
} // End of 'let isUnpredicable = 1 in'
def VSHTOS : AVConv1XInsS_Encode<0b11101, 0b11, 0b1010, 0b1010, 0, def VSHTOS : AVConv1XInsS_Encode<0b11101, 0b11, 0b1010, 0b1010, 0,
(outs SPR:$dst), (ins SPR:$a, fbits16:$fbits), (outs SPR:$dst), (ins SPR:$a, fbits16:$fbits),
IIC_fpCVTIS, "vcvt", ".f32.s16\t$dst, $a, $fbits", []>, IIC_fpCVTIS, "vcvt", ".f32.s16\t$dst, $a, $fbits", []>,
@ -2370,6 +2392,8 @@ def FCONSTH : VFPAI<(outs HPR:$Sd), (ins vfp_f16imm:$imm),
let Inst{11-8} = 0b1001; // Half precision let Inst{11-8} = 0b1001; // Half precision
let Inst{7-4} = 0b0000; let Inst{7-4} = 0b0000;
let Inst{3-0} = imm{3-0}; let Inst{3-0} = imm{3-0};
let isUnpredicable = 1;
} }
} }

View File

@ -6478,6 +6478,18 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() != Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
ARMCC::AL) { ARMCC::AL) {
return Warning(Loc, "predicated instructions should be in IT block"); return Warning(Loc, "predicated instructions should be in IT block");
} else if (!MCID.isPredicable()) {
// Check the instruction doesn't have a predicate operand anyway
// that it's not allowed to use. Sometimes this happens in order
// to keep instructions the same shape even though one cannot
// legally be predicated, e.g. vmul.f16 vs vmul.f32.
for (unsigned i = 0, e = MCID.getNumOperands(); i != e; ++i) {
if (MCID.OpInfo[i].isPredicate()) {
if (Inst.getOperand(i).getImm() != ARMCC::AL)
return Error(Loc, "instruction is not predicable");
break;
}
}
} }
// PC-setting instructions in an IT block, but not the last instruction of // PC-setting instructions in an IT block, but not the last instruction of

View File

@ -119,7 +119,7 @@ private:
mutable ITStatus ITBlock; mutable ITStatus ITBlock;
DecodeStatus AddThumbPredicate(MCInst&) const; DecodeStatus AddThumbPredicate(MCInst&) const;
void UpdateThumbVFPPredicate(MCInst&) const; void UpdateThumbVFPPredicate(DecodeStatus &, MCInst&) const;
}; };
} // end anonymous namespace } // end anonymous namespace
@ -630,6 +630,8 @@ ThumbDisassembler::AddThumbPredicate(MCInst &MI) const {
for (unsigned i = 0; i < NumOps; ++i, ++I) { for (unsigned i = 0; i < NumOps; ++i, ++I) {
if (I == MI.end()) break; if (I == MI.end()) break;
if (OpInfo[i].isPredicate()) { if (OpInfo[i].isPredicate()) {
if (CC != ARMCC::AL && !ARMInsts[MI.getOpcode()].isPredicable())
Check(S, SoftFail);
I = MI.insert(I, MCOperand::createImm(CC)); I = MI.insert(I, MCOperand::createImm(CC));
++I; ++I;
if (CC == ARMCC::AL) if (CC == ARMCC::AL)
@ -655,7 +657,8 @@ ThumbDisassembler::AddThumbPredicate(MCInst &MI) const {
// mode, the auto-generated decoder will give them an (incorrect) // mode, the auto-generated decoder will give them an (incorrect)
// predicate operand. We need to rewrite these operands based on the IT // predicate operand. We need to rewrite these operands based on the IT
// context as a post-pass. // context as a post-pass.
void ThumbDisassembler::UpdateThumbVFPPredicate(MCInst &MI) const { void ThumbDisassembler::UpdateThumbVFPPredicate(
DecodeStatus &S, MCInst &MI) const {
unsigned CC; unsigned CC;
CC = ITBlock.getITCC(); CC = ITBlock.getITCC();
if (CC == 0xF) if (CC == 0xF)
@ -668,6 +671,8 @@ void ThumbDisassembler::UpdateThumbVFPPredicate(MCInst &MI) const {
unsigned short NumOps = ARMInsts[MI.getOpcode()].NumOperands; unsigned short NumOps = ARMInsts[MI.getOpcode()].NumOperands;
for (unsigned i = 0; i < NumOps; ++i, ++I) { for (unsigned i = 0; i < NumOps; ++i, ++I) {
if (OpInfo[i].isPredicate() ) { if (OpInfo[i].isPredicate() ) {
if (CC != ARMCC::AL && !ARMInsts[MI.getOpcode()].isPredicable())
Check(S, SoftFail);
I->setImm(CC); I->setImm(CC);
++I; ++I;
if (CC == ARMCC::AL) if (CC == ARMCC::AL)
@ -773,7 +778,7 @@ DecodeStatus ThumbDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
decodeInstruction(DecoderTableVFP32, MI, Insn32, Address, this, STI); decodeInstruction(DecoderTableVFP32, MI, Insn32, Address, this, STI);
if (Result != MCDisassembler::Fail) { if (Result != MCDisassembler::Fail) {
Size = 4; Size = 4;
UpdateThumbVFPPredicate(MI); UpdateThumbVFPPredicate(Result, MI);
return Result; return Result;
} }
} }
@ -1110,16 +1115,19 @@ static DecodeStatus DecodeDPairSpacedRegisterClass(MCInst &Inst,
static DecodeStatus DecodePredicateOperand(MCInst &Inst, unsigned Val, static DecodeStatus DecodePredicateOperand(MCInst &Inst, unsigned Val,
uint64_t Address, const void *Decoder) { uint64_t Address, const void *Decoder) {
DecodeStatus S = MCDisassembler::Success;
if (Val == 0xF) return MCDisassembler::Fail; if (Val == 0xF) return MCDisassembler::Fail;
// AL predicate is not allowed on Thumb1 branches. // AL predicate is not allowed on Thumb1 branches.
if (Inst.getOpcode() == ARM::tBcc && Val == 0xE) if (Inst.getOpcode() == ARM::tBcc && Val == 0xE)
return MCDisassembler::Fail; return MCDisassembler::Fail;
if (Val != ARMCC::AL && !ARMInsts[Inst.getOpcode()].isPredicable())
Check(S, MCDisassembler::SoftFail);
Inst.addOperand(MCOperand::createImm(Val)); Inst.addOperand(MCOperand::createImm(Val));
if (Val == ARMCC::AL) { if (Val == ARMCC::AL) {
Inst.addOperand(MCOperand::createReg(0)); Inst.addOperand(MCOperand::createReg(0));
} else } else
Inst.addOperand(MCOperand::createReg(ARM::CPSR)); Inst.addOperand(MCOperand::createReg(ARM::CPSR));
return MCDisassembler::Success; return S;
} }
static DecodeStatus DecodeCCOutOperand(MCInst &Inst, unsigned Val, static DecodeStatus DecodeCCOutOperand(MCInst &Inst, unsigned Val,

View File

@ -0,0 +1,100 @@
; RUN: llc -O3 -mtriple=armv8a-none-eabi -mattr=+fullfp16 -o - %s | FileCheck %s
; RUN: llc -O3 -mtriple=thumbv8a-none-eabi -mattr=+fullfp16 -arm-no-restrict-it -o - %s | FileCheck %s
; Require the vmul.f16 not to be predicated, because it's illegal to
; do so with fp16 instructions
define half @conditional_fmul_f16(half* %p) {
; CHECK-LABEL: conditional_fmul_f16:
; CHECK: vmul.f16
entry:
%p1 = getelementptr half, half* %p, i32 1
%a = load half, half* %p, align 2
%threshold = load half, half* %p1, align 2
%flag = fcmp ogt half %a, %threshold
br i1 %flag, label %mul, label %out
mul:
%p2 = getelementptr half, half* %p, i32 2
%mult = load half, half* %p2, align 2
%b = fmul half %a, %mult
br label %out
out:
%sel = phi half [ %a, %entry ], [ %b, %mul ]
ret half %sel
}
; Expect that the corresponding vmul.f32 _will_ be predicated (to make
; sure the previous test is really testing something)
define float @conditional_fmul_f32(float* %p) {
; CHECK-LABEL: conditional_fmul_f32:
; CHECK: vmulgt.f32
entry:
%p1 = getelementptr float, float* %p, i32 1
%a = load float, float* %p, align 2
%threshold = load float, float* %p1, align 2
%flag = fcmp ogt float %a, %threshold
br i1 %flag, label %mul, label %out
mul:
%p2 = getelementptr float, float* %p, i32 2
%mult = load float, float* %p2, align 2
%b = fmul float %a, %mult
br label %out
out:
%sel = phi float [ %a, %entry ], [ %b, %mul ]
ret float %sel
}
; Require the two comparisons to be done with unpredicated vcmp.f16
; instructions (again, it is illegal to predicate them)
define void @chained_comparisons_f16(half* %p) {
; CHECK-LABEL: chained_comparisons_f16:
; CHECK: vcmp.f16
; CHECK: vcmp.f16
entry:
%p1 = getelementptr half, half* %p, i32 1
%a = load half, half* %p, align 2
%b = load half, half* %p1, align 2
%aflag = fcmp oeq half %a, 0xH0000
%bflag = fcmp oeq half %b, 0xH0000
%flag = or i1 %aflag, %bflag
br i1 %flag, label %call, label %out
call:
call void @external_function()
br label %out
out:
ret void
}
; Again, do the corresponding test with 32-bit floats and check that
; the second comparison _is_ predicated on the result of the first.
define void @chained_comparisons_f32(float* %p) {
; CHECK-LABEL: chained_comparisons_f32:
; CHECK: vcmp.f32
; CHECK: vcmpne.f32
entry:
%p1 = getelementptr float, float* %p, i32 1
%a = load float, float* %p, align 2
%b = load float, float* %p1, align 2
%aflag = fcmp oeq float %a, 0x00000000
%bflag = fcmp oeq float %b, 0x00000000
%flag = or i1 %aflag, %bflag
br i1 %flag, label %call, label %out
call:
call void @external_function()
br label %out
out:
ret void
}
declare void @external_function()

View File

@ -0,0 +1,113 @@
@ RUN: not llvm-mc -triple armv8a-none-eabi -mattr=+fullfp16 < %s 2>&1 | FileCheck %s
@ RUN: not llvm-mc -triple armv8a-none-eabi -mattr=+fullfp16,+thumb-mode -arm-implicit-it always < %s 2>&1 | FileCheck %s
vaddeq.f16 s0, s1, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vsubne.f16 s0, s1, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vdivmi.f16 s0, s1, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vmulpl.f16 s0, s1, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vnmulvs.f16 s0, s1, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vmlavc.f16 s1, s2, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vmlshs.f16 s1, s2, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vnmlalo.f16 s1, s2, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vnmlscs.f16 s1, s2, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vcmpcc.f16 s0, s1
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vcmphi.f16 s2, #0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vcmpels.f16 s1, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vcmpege.f16 s0, #0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vabslt.f16 s0, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vneggt.f16 s0, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vsqrtle.f16 s0, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vcvteq.f16.s32 s0, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vcvtne.u32.f16 s0, s0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vcvtrmi.s32.f16 s0, s1
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vrintzhs.f16 s3, s24
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vrintrlo.f16 s0, s9
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vrintxcs.f16 s10, s14
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vfmalt.f16 s2, s7, s4
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vfmsgt.f16 s2, s7, s4
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vfnmale.f16 s2, s7, s4
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vfnmseq.f16 s2, s7, s4
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vldrpl.16 s1, [pc, #6]
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vldrvs.16 s2, [pc, #510]
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vldrvc.16 s3, [pc, #-510]
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vldrhs.16 s4, [r4, #-18]
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vstrlo.16 s1, [pc, #6]
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vstrcs.16 s2, [pc, #510]
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vstrcc.16 s3, [pc, #-510]
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vstrhi.16 s4, [r4, #-18]
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vmovls.f16 s0, #1.0
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vmovge.f16 s1, r2
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable
vmovlt.f16 r3, s4
@ CHECK: [[@LINE-1]]:3: error: instruction is not predicable

View File

@ -0,0 +1,6 @@
# RUN: llvm-mc -disassemble -triple armv8a-none-eabi -mattr=+fullfp16 -show-encoding < %s 2>&1 | FileCheck %s
# CHECK: [[@LINE+1]]:2: warning: potentially undefined instruction encoding
[0x80,0x09,0x30,0xae]
# CHECK-NOT: [[@LINE+1]]:2: warning
[0x80,0x0a,0x30,0xae]

View File

@ -0,0 +1,9 @@
# RUN: llvm-mc -disassemble -triple thumbv8a-none-eabi -mattr=+fullfp16,+thumb-mode -show-encoding < %s 2>&1 | FileCheck %s
# CHECK: [[@LINE+2]]:2: warning: potentially undefined instruction encoding
[0xc8,0xbf]
[0x30,0xee,0x81,0x09]
# CHECK-NOT: [[@LINE+2]]:2: warning
[0xc8,0xbf]
[0x30,0xee,0x81,0x0a]

View File

@ -377,7 +377,8 @@ CodeGenInstruction::CodeGenInstruction(Record *R)
isAdd = R->getValueAsBit("isAdd"); isAdd = R->getValueAsBit("isAdd");
isTrap = R->getValueAsBit("isTrap"); isTrap = R->getValueAsBit("isTrap");
canFoldAsLoad = R->getValueAsBit("canFoldAsLoad"); canFoldAsLoad = R->getValueAsBit("canFoldAsLoad");
isPredicable = Operands.isPredicable || R->getValueAsBit("isPredicable"); isPredicable = !R->getValueAsBit("isUnpredicable") && (
Operands.isPredicable || R->getValueAsBit("isPredicable"));
isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress"); isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress");
isCommutable = R->getValueAsBit("isCommutable"); isCommutable = R->getValueAsBit("isCommutable");
isTerminator = R->getValueAsBit("isTerminator"); isTerminator = R->getValueAsBit("isTerminator");