diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -456,7 +456,11 @@ 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. diff --git a/llvm/lib/Target/ARM/ARMInstrFormats.td b/llvm/lib/Target/ARM/ARMInstrFormats.td --- a/llvm/lib/Target/ARM/ARMInstrFormats.td +++ b/llvm/lib/Target/ARM/ARMInstrFormats.td @@ -1555,6 +1555,8 @@ // 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. @@ -1902,6 +1904,8 @@ 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 @@ -1930,6 +1934,8 @@ 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 @@ -1956,6 +1962,8 @@ 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 @@ -1985,6 +1993,8 @@ 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 diff --git a/llvm/lib/Target/ARM/ARMInstrVFP.td b/llvm/lib/Target/ARM/ARMInstrVFP.td --- a/llvm/lib/Target/ARM/ARMInstrVFP.td +++ b/llvm/lib/Target/ARM/ARMInstrVFP.td @@ -129,6 +129,7 @@ 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))]>, @@ -148,6 +149,7 @@ 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)]>, @@ -451,7 +453,7 @@ multiclass vsel_inst 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"), @@ -479,7 +481,8 @@ defm VSELVS : vsel_inst<"vs", 0b01, 6>; multiclass vmaxmin_inst { - 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"), @@ -947,7 +950,8 @@ multiclass vrint_inst_anpm 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"), @@ -1012,7 +1016,7 @@ 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", []>, @@ -1221,6 +1225,8 @@ let Inst{6-5} = 0b00; let Inst{3-0} = 0b0000; + + let isUnpredicable = 1; } // Move R->H, clearing top 16 bits @@ -1241,6 +1247,8 @@ let Inst{6-5} = 0b00; let Inst{3-0} = 0b0000; + + let isUnpredicable = 1; } // FMRDH: SPR -> GPR @@ -1347,6 +1355,7 @@ []>, Sched<[WriteFPCVT]> { let Inst{7} = 1; // s32 + let isUnpredicable = 1; } def : VFPNoNEONPat<(f16 (sint_to_fp GPR:$a)), @@ -1392,6 +1401,7 @@ []>, Sched<[WriteFPCVT]> { let Inst{7} = 0; // u32 + let isUnpredicable = 1; } def : VFPNoNEONPat<(f16 (uint_to_fp GPR:$a)), @@ -1496,6 +1506,7 @@ []>, Sched<[WriteFPCVT]> { let Inst{7} = 1; // Z bit + let isUnpredicable = 1; } def : VFPNoNEONPat<(i32 (fp_to_sint HPR:$a)), @@ -1542,6 +1553,7 @@ []>, Sched<[WriteFPCVT]> { let Inst{7} = 1; // Z bit + let isUnpredicable = 1; } def : VFPNoNEONPat<(i32 (fp_to_uint HPR:$a)), @@ -1571,6 +1583,7 @@ []>, Sched<[WriteFPCVT]> { let Inst{7} = 0; // Z bit + let isUnpredicable = 1; } def VTOUIRD : AVConv1IsD_Encode<0b11101, 0b11, 0b1100, 0b1011, @@ -1595,6 +1608,7 @@ []>, Sched<[WriteFPCVT]> { let Inst{7} = 0; // Z bit + let isUnpredicable = 1; } } @@ -1642,6 +1656,8 @@ 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", []>, @@ -1666,6 +1682,8 @@ 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", []>, @@ -1721,6 +1739,8 @@ // 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", []>, @@ -1745,6 +1765,8 @@ 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", []>, @@ -2370,6 +2392,8 @@ let Inst{11-8} = 0b1001; // Half precision let Inst{7-4} = 0b0000; let Inst{3-0} = imm{3-0}; + + let isUnpredicable = 1; } } diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -6478,6 +6478,18 @@ 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 diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp --- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -119,7 +119,7 @@ mutable ITStatus ITBlock; DecodeStatus AddThumbPredicate(MCInst&) const; - void UpdateThumbVFPPredicate(MCInst&) const; + void UpdateThumbVFPPredicate(DecodeStatus &, MCInst&) const; }; } // end anonymous namespace @@ -630,6 +630,8 @@ 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) @@ -655,7 +657,8 @@ // 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) @@ -668,6 +671,8 @@ 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) @@ -773,7 +778,7 @@ decodeInstruction(DecoderTableVFP32, MI, Insn32, Address, this, STI); if (Result != MCDisassembler::Fail) { Size = 4; - UpdateThumbVFPPredicate(MI); + UpdateThumbVFPPredicate(Result, MI); return Result; } } @@ -1110,16 +1115,19 @@ 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, diff --git a/llvm/test/CodeGen/ARM/fp16-no-condition.ll b/llvm/test/CodeGen/ARM/fp16-no-condition.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/ARM/fp16-no-condition.ll @@ -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() diff --git a/llvm/test/MC/ARM/fullfp16-nopred.s b/llvm/test/MC/ARM/fullfp16-nopred.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ARM/fullfp16-nopred.s @@ -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 diff --git a/llvm/test/MC/Disassembler/ARM/fullfp16-arm-nopred.txt b/llvm/test/MC/Disassembler/ARM/fullfp16-arm-nopred.txt new file mode 100644 --- /dev/null +++ b/llvm/test/MC/Disassembler/ARM/fullfp16-arm-nopred.txt @@ -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] diff --git a/llvm/test/MC/Disassembler/ARM/fullfp16-thumb-nopred.txt b/llvm/test/MC/Disassembler/ARM/fullfp16-thumb-nopred.txt new file mode 100644 --- /dev/null +++ b/llvm/test/MC/Disassembler/ARM/fullfp16-thumb-nopred.txt @@ -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] diff --git a/llvm/utils/TableGen/CodeGenInstruction.cpp b/llvm/utils/TableGen/CodeGenInstruction.cpp --- a/llvm/utils/TableGen/CodeGenInstruction.cpp +++ b/llvm/utils/TableGen/CodeGenInstruction.cpp @@ -353,7 +353,8 @@ 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");