bit isCommutable = 0; // Is this 3 operand instruction commutable?
bit isTerminator = 0; // Is this part of the terminator for a basic block?
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 usesCustomInserter = 0; // Pseudo instr needing special help.
bit hasPostISelHook = 0; // To be *adjusted* after isel by target hook.
// Loads & stores operate on both NEON and VFP pipelines.
let D = VFPNeonDomain;
+
+ let isUnpredicable = 1; // FP16 instructions cannot in general be conditional
}
// VFP Load / store multiple pseudo instructions.
let Inst{11-8} = 0b1001; // Half precision
let Inst{7-6} = opcod4;
let Inst{4} = opcod5;
+
+ let isUnpredicable = 1; // FP16 instructions cannot in general be conditional
}
// Half precision, unary, non-predicated
let Inst{11-8} = 0b1001; // Half precision
let Inst{7-6} = opcod4;
let Inst{4} = opcod5;
+
+ let isUnpredicable = 1; // FP16 instructions cannot in general be conditional
}
// Half precision, binary
let Inst{11-8} = 0b1001; // Half precision
let Inst{6} = op6;
let Inst{4} = op4;
+
+ let isUnpredicable = 1; // FP16 instructions cannot in general be conditional
}
// Half precision, binary, not predicated
let Inst{11-8} = 0b1001; // Half precision
let Inst{6} = opcod3;
let Inst{4} = 0;
+
+ let isUnpredicable = 1; // FP16 instructions cannot in general be conditional
}
// VFP conversion instructions
let D = VFPNeonDomain;
}
+let isUnpredicable = 1 in
def VLDRH : AHI5<0b1101, 0b01, (outs HPR:$Sd), (ins addrmode5fp16:$addr),
IIC_fpLoad16, "vldr", ".16\t$Sd, $addr",
[(set HPR:$Sd, (alignedload16 addrmode5fp16:$addr))]>,
let D = VFPNeonDomain;
}
+let isUnpredicable = 1 in
def VSTRH : AHI5<0b1101, 0b00, (outs), (ins HPR:$Sd, addrmode5fp16:$addr),
IIC_fpStore16, "vstr", ".16\t$Sd, $addr",
[(alignedstore16 HPR:$Sd, addrmode5fp16:$addr)]>,
multiclass vsel_inst<string op, bits<2> opc, int CC> {
let DecoderNamespace = "VFPV8", PostEncoderMethod = "",
- Uses = [CPSR], AddedComplexity = 4 in {
+ Uses = [CPSR], AddedComplexity = 4, isUnpredicable = 1 in {
def H : AHbInp<0b11100, opc, 0,
(outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm),
NoItinerary, !strconcat("vsel", op, ".f16\t$Sd, $Sn, $Sm"),
defm VSELVS : vsel_inst<"vs", 0b01, 6>;
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,
(outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm),
NoItinerary, !strconcat(op, ".f16\t$Sd, $Sn, $Sm"),
multiclass vrint_inst_anpm<string opc, bits<2> rm,
SDPatternOperator node = null_frag> {
- let PostEncoderMethod = "", DecoderNamespace = "VFPV8" in {
+ let PostEncoderMethod = "", DecoderNamespace = "VFPV8",
+ isUnpredicable = 1 in {
def H : AHuInp<0b11101, 0b11, 0b1000, 0b01, 0,
(outs SPR:$Sd), (ins SPR:$Sm),
NoItinerary, !strconcat("vrint", opc, ".f16\t$Sd, $Sm"),
IIC_fpUNA32, "vmov", ".f32\t$Sd, $Sm", []>;
} // isMoveReg
-let PostEncoderMethod = "", DecoderNamespace = "VFPV8" in {
+let PostEncoderMethod = "", DecoderNamespace = "VFPV8", isUnpredicable = 1 in {
def VMOVH : ASuInp<0b11101, 0b11, 0b0000, 0b01, 0,
(outs SPR:$Sd), (ins SPR:$Sm),
IIC_fpUNA16, "vmovx.f16\t$Sd, $Sm", []>,
let Inst{6-5} = 0b00;
let Inst{3-0} = 0b0000;
+
+ let isUnpredicable = 1;
}
// Move R->H, clearing top 16 bits
let Inst{6-5} = 0b00;
let Inst{3-0} = 0b0000;
+
+ let isUnpredicable = 1;
}
// FMRDH: SPR -> GPR
[]>,
Sched<[WriteFPCVT]> {
let Inst{7} = 1; // s32
+ let isUnpredicable = 1;
}
def : VFPNoNEONPat<(f16 (sint_to_fp GPR:$a)),
[]>,
Sched<[WriteFPCVT]> {
let Inst{7} = 0; // u32
+ let isUnpredicable = 1;
}
def : VFPNoNEONPat<(f16 (uint_to_fp GPR:$a)),
[]>,
Sched<[WriteFPCVT]> {
let Inst{7} = 1; // Z bit
+ let isUnpredicable = 1;
}
def : VFPNoNEONPat<(i32 (fp_to_sint HPR:$a)),
[]>,
Sched<[WriteFPCVT]> {
let Inst{7} = 1; // Z bit
+ let isUnpredicable = 1;
}
def : VFPNoNEONPat<(i32 (fp_to_uint HPR:$a)),
[]>,
Sched<[WriteFPCVT]> {
let Inst{7} = 0; // Z bit
+ let isUnpredicable = 1;
}
def VTOUIRD : AVConv1IsD_Encode<0b11101, 0b11, 0b1100, 0b1011,
[]>,
Sched<[WriteFPCVT]> {
let Inst{7} = 0; // Z bit
+ let isUnpredicable = 1;
}
}
let Predicates = [HasVFP2, HasDPVFP];
}
+let isUnpredicable = 1 in {
+
def VTOSHH : AVConv1XInsS_Encode<0b11101, 0b11, 0b1110, 0b1001, 0,
(outs SPR:$dst), (ins SPR:$a, fbits16:$fbits),
IIC_fpCVTHI, "vcvt", ".s16.f16\t$dst, $a, $fbits", []>,
Requires<[HasFullFP16]>,
Sched<[WriteFPCVT]>;
+} // End of 'let isUnpredicable = 1 in'
+
def VTOSHS : AVConv1XInsS_Encode<0b11101, 0b11, 0b1110, 0b1010, 0,
(outs SPR:$dst), (ins SPR:$a, fbits16:$fbits),
IIC_fpCVTSI, "vcvt", ".s16.f32\t$dst, $a, $fbits", []>,
// Fixed-Point to FP:
+let isUnpredicable = 1 in {
+
def VSHTOH : AVConv1XInsS_Encode<0b11101, 0b11, 0b1010, 0b1001, 0,
(outs SPR:$dst), (ins SPR:$a, fbits16:$fbits),
IIC_fpCVTIH, "vcvt", ".f16.s16\t$dst, $a, $fbits", []>,
Requires<[HasFullFP16]>,
Sched<[WriteFPCVT]>;
+} // End of 'let isUnpredicable = 1 in'
+
def VSHTOS : AVConv1XInsS_Encode<0b11101, 0b11, 0b1010, 0b1010, 0,
(outs SPR:$dst), (ins SPR:$a, fbits16:$fbits),
IIC_fpCVTIS, "vcvt", ".f32.s16\t$dst, $a, $fbits", []>,
let Inst{11-8} = 0b1001; // Half precision
let Inst{7-4} = 0b0000;
let Inst{3-0} = imm{3-0};
+
+ let isUnpredicable = 1;
}
}
Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
ARMCC::AL) {
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
mutable ITStatus ITBlock;
DecodeStatus AddThumbPredicate(MCInst&) const;
- void UpdateThumbVFPPredicate(MCInst&) const;
+ void UpdateThumbVFPPredicate(DecodeStatus &, MCInst&) const;
};
} // end anonymous namespace
for (unsigned i = 0; i < NumOps; ++i, ++I) {
if (I == MI.end()) break;
if (OpInfo[i].isPredicate()) {
+ if (CC != ARMCC::AL && !ARMInsts[MI.getOpcode()].isPredicable())
+ Check(S, SoftFail);
I = MI.insert(I, MCOperand::createImm(CC));
++I;
if (CC == ARMCC::AL)
// mode, the auto-generated decoder will give them an (incorrect)
// predicate operand. We need to rewrite these operands based on the IT
// context as a post-pass.
-void ThumbDisassembler::UpdateThumbVFPPredicate(MCInst &MI) const {
+void ThumbDisassembler::UpdateThumbVFPPredicate(
+ DecodeStatus &S, MCInst &MI) const {
unsigned CC;
CC = ITBlock.getITCC();
if (CC == 0xF)
unsigned short NumOps = ARMInsts[MI.getOpcode()].NumOperands;
for (unsigned i = 0; i < NumOps; ++i, ++I) {
if (OpInfo[i].isPredicate() ) {
+ if (CC != ARMCC::AL && !ARMInsts[MI.getOpcode()].isPredicable())
+ Check(S, SoftFail);
I->setImm(CC);
++I;
if (CC == ARMCC::AL)
decodeInstruction(DecoderTableVFP32, MI, Insn32, Address, this, STI);
if (Result != MCDisassembler::Fail) {
Size = 4;
- UpdateThumbVFPPredicate(MI);
+ UpdateThumbVFPPredicate(Result, MI);
return Result;
}
}
static DecodeStatus DecodePredicateOperand(MCInst &Inst, unsigned Val,
uint64_t Address, const void *Decoder) {
+ DecodeStatus S = MCDisassembler::Success;
if (Val == 0xF) return MCDisassembler::Fail;
// AL predicate is not allowed on Thumb1 branches.
if (Inst.getOpcode() == ARM::tBcc && Val == 0xE)
return MCDisassembler::Fail;
+ if (Val != ARMCC::AL && !ARMInsts[Inst.getOpcode()].isPredicable())
+ Check(S, MCDisassembler::SoftFail);
Inst.addOperand(MCOperand::createImm(Val));
if (Val == ARMCC::AL) {
Inst.addOperand(MCOperand::createReg(0));
} else
Inst.addOperand(MCOperand::createReg(ARM::CPSR));
- return MCDisassembler::Success;
+ return S;
}
static DecodeStatus DecodeCCOutOperand(MCInst &Inst, unsigned Val,
--- /dev/null
+; 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()
--- /dev/null
+@ 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
--- /dev/null
+# 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]
--- /dev/null
+# 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]
isAdd = R->getValueAsBit("isAdd");
isTrap = R->getValueAsBit("isTrap");
canFoldAsLoad = R->getValueAsBit("canFoldAsLoad");
- isPredicable = Operands.isPredicable || R->getValueAsBit("isPredicable");
+ isPredicable = !R->getValueAsBit("isUnpredicable") && (
+ Operands.isPredicable || R->getValueAsBit("isPredicable"));
isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress");
isCommutable = R->getValueAsBit("isCommutable");
isTerminator = R->getValueAsBit("isTerminator");